Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to multiple tables in rails

I'm sure this is a relatively simple question, and there must be a good sensible rails way of doing it, but I'm not sure what it is.

Basically I'm adding books to a database, and I want to store the Author in a separate table. So I have a table called authors which is referenced by the table books.

I want to create a rails form for adding a book, and I'd like it to be just a simple form for Author, Title, Publisher etc, and if it finds the author already in the authors table then it should just reference that record, and if it isn't in the authors table then it should add a new record and reference it.

I'm sure there's an easy way of doing this in rails - but I can't seem to find it.

Cheers,

Robin

like image 254
robintw Avatar asked Oct 28 '08 19:10

robintw


3 Answers

Assuming that your form passes an author_name and a book hash with the book attributes, you could do the following in your controller:

@author = Author.find_or_create_by_name(params[:author_name])
@book = Book.new(params[:book])
@book.author = @author
@book.save

This will find an author by that name, or create one, then assign that author to the book that's created.

Note: This also assumes that authors can be uniquely identified by their name, and this usually isn't the case. There could be multiple guys namned "Steven King" out there, for instance, and only one of them wrote The Shining

like image 63
Micah Avatar answered Nov 08 '22 17:11

Micah


I suggest you watch the Complex Forms Series of Railscasts here.

like image 5
Honza Avatar answered Nov 08 '22 19:11

Honza


robintw's comment to Micah's answer:

This looks like a good way to do it - although I am surprised in some ways that Rails doesn't do it a bit more automatically

It's four lines! How much more automatically can Rails make it? It's a framework not a human being. :)

And here it is in two:

@author = Author.find_or_create_by_name(params[:author_name])
@book = Book.create params[:book].merge({:author_id => @author.id})

And Honza's answer has a lot of merit:

class Book < ActiveRecord::Base
  ...
  def author_name=(author_name)
    self.author = Author.find_or_create_by_name author_name
  end
end

With this example, and assuming your form has a parameter like "book[author_name]", your code is just:

@book = Book.create params[:book]

Wowzers.

like image 1
Ian Terrell Avatar answered Nov 08 '22 18:11

Ian Terrell