Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HABTM and accepts_nested_attributes_for

Say I have two models, Book and Author with a has_and_belongs_to_many relationship between them.

What I want to do is to be able to add author names in the book form, and on submit to either link the authors with the book if they already exist, or create them if they don't.

I also want to do the same with the author form: add book names and on submit either link them if they exist, or create them if they don't.

On edit, however, I want to neither be able to edit nor delete the nested objects, only remove the associations.

Is accepts_nested_attributes_for suitable for this, or is there another way?

I managed to accomplish this by following the Complex Forms railscasts on Rails 2, but I'm looking for a more elegant solution for Rails 3.

like image 339
Marjan Avatar asked Feb 02 '23 21:02

Marjan


1 Answers

I'm not sure why so many people use has_and_belongs_to_many, which is a relic from Rails 1, instead of using has_many ..., :through except that it's probably in a lot of old reference books and tutorials. The big difference between the two approaches is the first uses a compound key to identify them, the second a first-class model.

If you redefine your relationship, you can manage on the intermediate model level. For instance, you can add and remove BookAuthor records instead of has_and_belongs_to_many links which are notoriously difficult to tweak on an individual basis.

You can create a simple model:

class BookAuthor < ActiveRecord::Base
  belongs_to :book
  belongs_to :author
end

Each of your other models is now more easily linked:

class Book < ActiveRecord::Base
  has_many :book_authors
  has_many :authors, :through => :book_authors
end

class Author < ActiveRecord::Base
  has_many :book_authors
  has_many :books, :through => :book_authors
end

On your nested form, manage the book_authors relationship directly, adding and removing those as required.

like image 163
tadman Avatar answered Feb 05 '23 15:02

tadman