# Table relations and record creation

**URL:** <https://www.ruby-forum.com/t/table-relations-and-record-creation/106870>\
**Category:** Rails\
**Created:** [June 14, 2007, 9:23pm UTC](https://www.ruby-forum.com/t/table-relations-and-record-creation/106870 "2007-06-14T21:23:42Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tayknight](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/da6949/32.png) [@tayknight](https://www.ruby-forum.com/u/tayknight)\
**Post date:** [June 14, 2007, 9:23pm UTC](https://www.ruby-forum.com/t/table-relations-and-record-creation/106870/1 "2007-06-14T21:23:42Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![tayknight](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/da6949/32.png) [@tayknight](https://www.ruby-forum.com/u/tayknight)\
**Post date:** [June 15, 2007, 12:14am UTC](https://www.ruby-forum.com/t/table-relations-and-record-creation/106870/2 "2007-06-15T00:14:28Z")

</div>

That does help. I didn’t know about the :through and I didn’t think to  
use an association table. Thanks for the help.

---

<div class="post-metadata">

**Author:** ![tayknight](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/da6949/32.png) [@tayknight](https://www.ruby-forum.com/u/tayknight)\
**Post date:** [June 14, 2007, 11:39pm UTC](https://www.ruby-forum.com/t/table-relations-and-record-creation/106870/3 "2007-06-14T23:39:18Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![tayknight](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/da6949/32.png) [@tayknight](https://www.ruby-forum.com/u/tayknight)\
**Post date:** [June 15, 2007, 12:38am UTC](https://www.ruby-forum.com/t/table-relations-and-record-creation/106870/4 "2007-06-15T00:38:31Z")

</div>

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.
