user2490003
user2490003

Reputation: 11890

Returning another model's results in an ActiveRecord query

Say I have a simple one-to-many relationship between two tables

class Table < ActiveRecord:Base
  has_may :legs
end

class Leg < ActiveRecord:Base
  belongs_to :table
end

When I run the following query, it returns a list of Table model objects.

Table.joins(:legs).where("legs.type = 'short'")
# => [<Table id: 1>, <Table id: 1>]

Because a Table can have many legs that satisfy the above query criteria, I sometimes receive duplicate Table instances in my result.

It would be much easier (especially in situations much more complex than this) to be able to query on Table but have it return a result set of Leg objects

Table.joins(:legs).where("legs.type = 'short'")
# => [<Leg id: 1>, <Leg id: 2>]

Is this possible?

Thanks!

Edit: To be clear, I'm aware I could go through and map each object to get the result I want. But that gets tricky with one-to-many relationships. And so I'm looking for a more "native" ActiveRecord way to do it

Edit 2: I'm also aware I can query directly on Leg - that's not the question. The heart of the question is "is it possible to query on Table but return a list of Leg objects?". The context for this is beyond the scope of the question, but I've come across a need for it when querying polymorphic associations when one model maps to many other model types.

Upvotes: 5

Views: 1485

Answers (4)

Prostko
Prostko

Reputation: 23

Table.joins(:legs)
     .where(legs: { type: 'short' })
     .select('DISTINCT legs.*')

This will instantiate a Table object, with all of the fields of Leg. Which is weird, but it will work because of duck-typing.

Upvotes: 0

An Nguyen Dang
An Nguyen Dang

Reputation: 11

This is a weird workaround but you can do:

Leg.find_by_sql(Table.joins(:legs).where("legs.type = 'short'").select("DISTINCT legs.*").to_sql)

which convert the core query to raw sql, then run that raw sql on the leg model. As long as the result have all the field of the model getting queried.

Upvotes: 1

sa77
sa77

Reputation: 3603

you can write a class method on your Table model

def self.short_legs
  Leg.where(type: 'short')
end

then call it as Table.short_legs

Upvotes: 0

Brad
Brad

Reputation: 738

I think you simply want: Leg.where(type: 'short').

Upvotes: 0

Related Questions