Forum: Ruby on Rails table relations and record creation

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ac25a42f3e336878aa9aca1b88118dbb?d=identicon&s=25 tayknight (Guest)
on 2007-06-14 21:23
(Received via mailing list)
I have a situation where I have three models, Album, Artists and
Songs:
class Album < ActiveRecord::Base
  belongs_to :song
end

class Artist < ActiveRecord::Base
  belongs_to :song
end

class Song < ActiveRecord::Base
  belongs_to :artist
end

So, an album can have songs that have artists.

The problem is that on the Album create form, the user is allowed to
enter all three values. So, the user may enter an existing album that
has a new song by a new artist. Or they have enter a new album that
has an existing song by an existing artist.

I can't figure out how to manage this create in the controller. So,
far I have:
def create
    @artist = Artist.find_or_create_by_name(params[:artists][:name])

    @song = Song.find_by_name(params[:songs][:name])
    if @song.nil?
          @song = Song.new(:name => params[:songs][:name], :artist_id
=> @artist.id)
          if !@song.save
            flash[:error] = "Couldn't create song"
                  redirect_to :action => 'new'
          end
    end

    @album = Album.new()
    @album.item_id = @item.id
    @album.song_id = @song.id
    if @album.save
      flash[:notice] = 'Album was successfully created.'
      redirect_to :action => 'show', :id => @album.id
    else
      render :action => 'new'
    end
end

This seems to work, but it feels kludgy and I'm not sure if there is
another, more Rails appropriate way to do it. Any suggestions?
D7c511ce5025d37b8c6bd9134e0f2bd9?d=identicon&s=25 Thorsten (Guest)
on 2007-06-14 23:39
(Received via mailing list)
uhm your code is a bit confusing ...

1) where does @item come from? it's not created in the "create"
action... some before filter? what is it?
2) you say users can enter an existing album, but you always create a
new one ? and doesn't it get a name or something?
3) how are your associations set up?

while because of the above, i'm not sure what you exactly want or
need, i was in the mood to type some stuff out as i like associations
problems. If it doesn't suit your needs exactly maybe you can get some
hints out of it:

First the associations, i guess how you have (or should have) set them
up, due to above unclarities:

lass Artist < ActiveRecord::Base
  has_many :songs
  has_many :albums, :through => :songs
end

class Song < ActiveRecord::Base
  belongs_to :artist
  has_many :album_appearances
  has_many :albums, :through => :album_appearances
end

class AlbumAppearances  < ActiveRecord::Base
  belongs_to :album
  belongs_to :song
end

class Album < ActiveRecord::Base
  has_many :songs
  has_many :artists, :through => :songs
end
so the association works like this

Artist<->song<->song_appearance<->album

*********************
Now, the controller. I shortened the code for better readability, you
might add an error check here and there:

def create
  #find or create the Artist:
  @artist = Artist.find_or_create_by_name(params[:artist][:name])

  #we have the artist, now find the song by this artist if it exists,
if not, create a new one, associated to the artist:
  song = @artist.songs.find_by_name(params[:songs][:name])
  if @song = nil
    @song = @artist.songs.create(params[:song])
  end

  #Now we got the song, associated to the artist.
  #So we find or create the Album, and add the song to the
has_many :through relationship
  @album = Album.find_or_create_by_name(params[:albums][:name])
  @album.songs << @song #creates an association in the join table
"song_appearances"

  #Redirect to the Show page for the album:
  redirect_to action => 'show', :id => @album.id
end

Hope that helps
Ac25a42f3e336878aa9aca1b88118dbb?d=identicon&s=25 tayknight (Guest)
on 2007-06-15 00:14
(Received via mailing list)
That does help. I didn't know about the :through and I didn't think to
use an association table. Thanks for the help.
D7c511ce5025d37b8c6bd9134e0f2bd9?d=identicon&s=25 Thorsten (Guest)
on 2007-06-15 00:38
(Received via mailing list)
Glad i could help.

One more thing:

the "has many :albums" in the Artist class won't work i guess, it
slipped in there accidentally. ;)
The rest should be fine though.
This topic is locked and can not be replied to.