phauwn
phauwn

Reputation: 366

How to find instance of an object in a collection within a collection in rails

I'm trying to write an if statement that will find an instance of an object in a collection within another collection...

House 
has_many :occupants
Occupant 
has_many :shirts
belongs_to :house
Shirt
belongs_to :occupant

So if I want check if any of the occupants of house own a white shirt, I want to do something like this:

<% if @house.occuptants.shirts.where(:color => 'white') %>

However when I do that I get an error:

undefined method `shirts' for #< Occupant::ActiveRecord_Associations_CollectionProxy

I believe because occupants is a collection in this case, but I'm not sure what the correct approach or syntax should be.

Upvotes: 1

Views: 1377

Answers (2)

xploshioOn
xploshioOn

Reputation: 4115

Something simpler and that will help you later for different use cases is to add more to the relationships:

class House 
  has_many :occupants
  has_many :shirts, through: :occupants
end

class Occupant
  has_many :shirts
  belongs_to :house
  scope :females, -> { where(...) }   # This is homework for you: http://guides.rubyonrails.org/active_record_querying.html#scopes
end

class Shirt
  belongs_to :occupant
end

If you have a House instance:then you can check for occupants with white shirts as below:

<% if @house.shirts.where(color: 'white').exists? %>

and to check for female occupants with white color shirts, do:

<% if @house.occupants.females.select { |o| o.shirts.where(color: 'white').exists? } %>

Upvotes: 3

Ian Rodriguez
Ian Rodriguez

Reputation: 258

I would go for a presenter/decorator in this scenario.

Use draper to decorate the house object like:

# /app/decorators/house_decorator.rb
class HouseDecorator < Draper::Decorator
  def count_occupants_with_white_shirts
    object.occupants.joins(:shirts).where(shirts: { color: 'white' } ).count
  end
end

Then in your view:

<% if @house.count_occupants_with_white_shirts > 0 %>

Hope that helps.

NOTE: If you don't want an additional dependency(Draper) you can also put that method inside you House model

Upvotes: 0

Related Questions