0

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.

Geoff
  • 2,208
  • 1
  • 16
  • 17

1 Answers1

0

If anyone else is interested, something like this worked. In my real app, I went ahead and made it more generic though.

def build_book_awards(award_list)
  award_list.each_with_index do |award, idx|
    unless index = book_awards.find_index{|s| s.award == award}
      event_awards.build(:award_id => award.id)
      index = -1
    end
    book_awards.insert(idx, book_awards.delete_at(index))
  end
end

I still feel like I'm missing something because this seems far too useful to me not be included somehow.

Geoff
  • 2,208
  • 1
  • 16
  • 17