I am still struggling with appropriate ways to set associations in rails. I've finally reasoned that I want the model to do most of the work. My basic models are fairly simple. I have a model for books, a model for awards, and a model for book_awards which links the two. I want to create the book_awards from the book model.
class Book < ActiveRecord::Base
has_many :book_awards, :inverse_of :book
has_many :awards, :through => :book_awards
end
When I'm dealing with a new book, building the list of possible awards is pretty easy. It looks like this: (In each case award_list
is passed in as Award.some_scope
)
def build_book_awards(award_list)
award_list.each do |award|
book_awards.build(:award => award)
end
end
When dealing with an existing book though, I need to check if the association already exists. A fairly easy approach is like this:
def build_book_awards(award_list)
award_list.each do |award|
book_rewards.build(:award => award) if book_awards.find{|s| s.award == award}.nil?
end
end
The problem is that this will not list the awards in award order. Instead it will list existing book_awards first followed by awards the book has not won. For purely aesthetic reasons, I find this appalling. I want the associations to be listed in the same order every time.
Next I came up with the following code. This lists things in order and looks beautiful on the edit page, however it has the unacceptable side effect of deleting any existing associations if the user doesn't proceed with the update.
def build_book_awards(award_list)
current = book_awards.clone
book_awards.clear
award_list.each do |award|
book_award = current.find{|s| s.award == award}
if book_award
book_awards.push(book_award)
else
book_awards.build(:book => book)
end
end
end
The problem in my mind is that build creates an association and appends it to the end of the association list. I need a way to build it and then insert it wherever I want it.