Search code examples
rubyactiverecordsinatrasinatra-activerecord

ActiveRecord has_many :through doesn't assign value through


I am working with a song, genre and artist model. The classes look like below:

class Genre < ActiveRecord::Base
    has_many :song_genres
    has_many :songs, through: :song_genres
    has_many :artists, through: :songs
end

class Artist < ActiveRecord::Base
    has_many :songs
    has_many :genres, through: :songs
end

class Song < ActiveRecord::Base
    belongs_to :artist
    has_many :song_genres
    has_many :genres, through: :song_genres
end

class SongGenre < ActiveRecord::Base
    belongs_to :song
    belongs_to :genre
end

The problem I having is when I assign a song (with a genre already assigned) to an artist, the genre isn't available to the artist instance through artist.genres. Below is an example of what I mean:

song.genres << genre
=> [#<Genre:0x00007faf02b914b0 id: 2, name: "Pop">]
[10] pry(main)> song.genres
=> [#<Genre:0x00007faf02b914b0 id: 2, name: "Pop">]
[11] pry(main)> song.artist = artist
=> #<Artist:0x00007faf044cb048 id: 2, name: "James Blunt">
[12] pry(main)> artist.genres
=> []

Is this how ActiveRecord works? How can I get around this?


Solution

  • Okay, i got the problem here. You need to save your song record before calling artist.genres. Genres will not be assigned to the related artist unless you save it.

    > artist = Artist.new
     => #<Artist id: nil>
    
    > artist.save
     => true 
    
    > song = Song.new
     => #<Song id: nil, artist_id: nil>
    > song.artist = artist
     => #<Artist id: 1>
    
    > genre = Genre.new
     => #<Genre id: nil> 
    
    > song.genres << genre
     => #<ActiveRecord::Associations::CollectionProxy [#<Genre id: nil>]> 
    
    # Before saving `song`
    > artist.genres
      => #<ActiveRecord::Associations::CollectionProxy []> 
    
    > song.save
     => true 
    
    # After saving `song`
    > artist.genres
     => #<ActiveRecord::Associations::CollectionProxy [#<Genre id: 1>]>
    

    Let me know if it helps.