简体   繁体   中英

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?

Something like this should work, using includes :

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

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'])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM