Немного поиграв с этим, большая идея заключалась в том, чтобы поместить некоторую дополнительную информацию в таблицу соединений (в моем примере я называю это primary
).А затем прочитайте документы , чтобы понять, как сказать ActiveRecord
их использовать.
# setup active record
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
# some tables (migrations / schema)
ActiveRecord::Schema.define do
create_table(:artists) { |t| t.string :name}
create_table(:albums) { |t| t.string :name }
create_table :appearances do |t|
t.integer :artist_id
t.integer :album_id
t.boolean :primary, default: false # <-- join table specifies who is primary
end
end
# some models
class Artist < ActiveRecord::Base
has_many :appearances
has_many :albums, through: :appearances
end
class Appearance < ActiveRecord::Base
belongs_to :artist
belongs_to :album
end
class Album < ActiveRecord::Base
# three associations to appearances
has_many :all_appearances, class_name: 'Appearance'
has_many :primary_appearances, -> { where primary: true }, class_name: 'Appearance'
has_many :featured_appearances, -> { where primary: false }, class_name: 'Appearance'
# three associations to artists
has_many :all_artists, through: 'all_appearances', source: 'artist'
has_many :primary_artists, through: 'primary_appearances', source: 'artist'
has_many :featured_artists, through: 'featured_appearances', source: 'artist'
end
# some artists
dre = Artist.create! name: 'Dr. Dre'
dogg = Artist.create! name: 'Snoop Dogg'
slim = Artist.create! name: 'Eminem'
# some albums
weed = Album.create! name: 'The Chronic 2001',
primary_artists: [dre],
featured_artists: [dogg, slim]
show = Album.create! name: 'The Eminem Show',
primary_artists: [slim],
featured_artists: [dre]
# it understands the associations
weed.all_artists.pluck :name # => ["Dr. Dre", "Snoop Dogg", "Eminem"]
weed.primary_artists.pluck :name # => ["Dr. Dre"]
weed.featured_artists.pluck :name # => ["Snoop Dogg", "Eminem"]
# might be nice to add similar scoped associations to get from Artist to Album
weed # => #<Album id: 1, name: "The Chronic 2001">
.primary_artists # => #<ActiveRecord::Associations::CollectionProxy [#<Artist id: 1, name: "Dr. Dre">]>
.first # => #<Artist id: 1, name: "Dr. Dre">
.albums # => #<ActiveRecord::Associations::CollectionProxy [#<Album id: 1, name: "The Chronic 2001">, #<Album id: 2, name: "The Eminem Show">]>
.last # => #<Album id: 2, name: "The Eminem Show">
.primary_artists # => #<ActiveRecord::Associations::CollectionProxy [#<Artist id: 3, name: "Eminem">]>
.first # => #<Artist id: 3, name: "Eminem">