Reputation: 6466
I want to be able to return an AR relation by calling a method on another relation of different model objects. In other words, given a User
model which belongs_to
a House
model (which either has_one
or has_many
Users) I want to be able to take a relation of users
and do users.houses
, which should return the relation of house objects to which those users belong.
NOTE -- I'm not trying to create a user.houses
method (singular user), but rather a users.houses
method, which grabs all houses whose ids are among the list of all house_id
s in the list of users
. The idea is that this then allows me to call class/relation methods on that relation of houses: users.houses.house_class_method
.
I've tried doing this "manually":
class User
belongs_to :house
# Is there some AR Relationship I can declare that would
# write this method (correctly) for me?
def self.houses
House.where(id: pluck(:house_id))
end
end
House model:
class House
has_many :users
def self.addresses
map(&:address)
end
def address
"#{street_address}, #{city}"
end
end
Two issues, though:
This feels (maybe incorrectly) like something that should be declarable via a AR relationship.
It isn't working correctly. The trouble (as outlined in this
separate question) is that users.houses
works fine, but when I
do users.houses.addresses
,
the method is called on the House class, rather than the relation of
houses that users.houses
returns (!?!). As a consequence, I get an undefined method 'map' for <Class:0x1232132131>
error.
Is there a correct way to do this in Rails -- to essentially say that a relation belongs to another relation, or that a model belongs to another, on a relation level as well?
Thanks!
Upvotes: 0
Views: 466
Reputation: 199
Hmm, users
would be an Array
or ActiveRelation
, not of type User
I would recommend a static method on User:
def self.houses_for_users(users)
..
end
Upvotes: 0
Reputation: 572
You don't have to implement self.houses
; Rails does this for you.
In your User model (user.rb
), do the following
def User
has_many :houses
...
end
and in your House model
def House
belongs_to :user
...
end
from there on, some_user.houses
returns all the houses that belong to that user. Just make sure there is a user_id (integer) column in your Houses table.
Upvotes: 0
Reputation: 13057
Implementing has_and_belongs_to_many
relationship between User
and House
models might make it easier for accomplishing what you want.
class User
has_and_belongs_to_many :houses
...
end
class House
has_and_belongs_to_many :users
...
end
> user = User.find(user_id)
> user.houses # All houses the user belongs to
> house = House.find(house_id)
> house.users # All users belonging to the house
Upvotes: 1