ste
ste

Reputation: 3259

Rails: Find all records matching condition for any of the associated objects

I have the following Ruby on Rails entity:

Playlist:

class Playlist < ActiveRecord::Base {
                             :id => :integer,
                           :name => :string,
                     :created_at => :datetime,
                     :updated_at => :datetime,
                      :dimension => :string,
                          :title => :string,
                           :text => :string,
                          :price => :float,
       :playlist_image_file_name => :string,
    :playlist_image_content_type => :string,
       :playlist_image_file_size => :integer,
      :playlist_image_updated_at => :datetime,
                           :main => :boolean,
                         :action => :string,
                 :hairdresser_id => :integer
}

And Keyword:

class Keyword < ActiveRecord::Base {
             :id => :integer,
           :name => :string,
     :created_at => :datetime,
     :updated_at => :datetime,
    :preselected => :boolean
}

The relation between them is very simple: basically a Playlist object can have 0 or more keywords associated. Those are the models:

class Keyword < ActiveRecord::Base
  has_and_belongs_to_many :playlists
end

class Playlist < ActiveRecord::Base
  has_and_belongs_to_many :keywords

  has_attached_file :playlist_image, styles: {medium: "500x500", small: "200x200", thumb: "40x40"}, default_url: "/system/playlist_default.jpg"
  validates_attachment_content_type :playlist_image, content_type: /\Aimage\/.*\Z/
end

That allows me to do something like that:

Playlist.first.keywords

and retrieve all the keywords associated with the first playlist.

Now I would like to build a function to return all the playlists that have certain words as keywords and have "main" equals to true. For example all the playlist that have the keyword "Summer". I tryed with that:

Playlist.where(:main => true).map{|x| x.keywords.include? "Summer"}

But that returns only an array containing true or false depending if the related Playlist contains or not the keyword "Summer", I'm looking for something that return the whole playlist only if the array of keywords of that playlist include the word "summer". How can I achieve that?

Upvotes: 1

Views: 2859

Answers (2)

Long Nguyen
Long Nguyen

Reputation: 373

You should create scopes to increase reusability.

class Playlist < ActiveRecord::Base
  has_and_belongs_to_many :keywords

  scope :main, -> { where(main: true) }
  scope :with_key_words, -> (key_words) { joins(:keywords).where(keywords: {name: key_words}) }
end

To get all playlists satisfy your requirements, just:

Playlist.main.with_key_words(['Summer'])

Upvotes: 0

potashin
potashin

Reputation: 44581

Something like this should work, using includes:

Playlist.includes(:keywords)
        .where(playlists: {main: true}, keywords: {name: 'Summer'})

Upvotes: 2

Related Questions