Sasha
Sasha

Reputation: 6466

Active Record querying relation to get other relation

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_ids 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:

  1. This feels (maybe incorrectly) like something that should be declarable via a AR relationship.

  2. 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

Answers (3)

Dirk de Kok
Dirk de Kok

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

Adib Saad
Adib Saad

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

Prakash Murthy
Prakash Murthy

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

Related Questions