5

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

4 Answers 4

6

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the quick response! 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.
5

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

Comments

1

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.

Comments

0

This will eventually be automatic (according to this post, in Rails 2.2): http://ryandaigle.com/articles/2008/7/19/what-s-new-in-edge-rails-nested-models

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.