views:

1720

answers:

4

I have a rails app I'm trying to set up with sortable lists using the acts_as_list plugin. The position field in the db is getting updated, but when the page is rendered, the order is not considered. I'm looking for some help, I guess.

Here are my models...

class QuestionMembership < ActiveRecord::Base
  belongs_to :form
  belongs_to :question
  acts_as_list
end

class Form < ActiveRecord::Base
  has_many :question_memberships
  has_many :questions, :through => :question_memberships
end

class Question < ActiveRecord::Base
  has_many :question_memberships
  has_many :forms, :through => :question_memberships
  acts_as_list
end

And the sloppy view code that gives me the list...

<% @form.question_memberships.each do |qm| %>
  <% q_id = "question_#{qm.id}" %>
  <li class="question" id=<%= q_id %> >
    <div style="color: #999; font-size: 8pt">
      <%=h qm.question.content %>
    </div>
  </li>
  <%= draggable_element(q_id, :revert=>true) %>
<% end %>

The drag and drop works for the reordering. The position value updates in the DB for the QuestionMembership objects and the page actually shows the reorder correctly. The problem is that on a page reload, it defaults back to whatever order it feels like. I think it defaults to the question id for the order instead of the question_membership position, but I'm not sure.

Any ideas on how I can make it actually order on the initial render by the position field of the QuestionMembership?

+2  A: 

As soon as I post the question, I find the answer. I was missing the :order and :scope attributes on my models.

CJ
you should post the corrected code and accept your own answer.
Berek Bryan
+1  A: 

With Rails 2.3 you can set a default scope to always order by position:

acts_as_list :scope => <scope clause>
default_scope :order => :position

Note that this usage of scope is different than that of acts_as_list, which decides what to scope the list to.

Ian Terrell
A: 

The final version:

class QuestionMembership < ActiveRecord::Base
  belongs_to :form
  belongs_to :question
  acts_as_list :scope => :form
end

class Form < ActiveRecord::Base
  has_many :question_memberships, , :order => "position"
  has_many :questions, :through => :question_memberships
end

class Question < ActiveRecord::Base
  has_many :question_memberships, :order => "position"
  has_many :forms, :through => :question_memberships
  acts_as_list :scope => :form
end
CJ
A: 

I was having a terrible time working this out. Up until I found this example, I had been just using acts_as_list on the "Question" model. It would work, but Rails was getting confused when I tried to create new Questions.

I tried it this way, and I could create new objects, but it seemed that my app was confused about which model the "position" field should live.

Finally, I realized that, in my case, it was completely appropriate to use just the join model as the one to have the position field on, because this is exactly what the :scope keyword was for! It scopes the ordering of "Questions" to each "Form", which may be different per form. After this, I just left off the acts_as_list from the "question" model, and dealt with sorting based on grabbing the "QuestionMembership" instances (and then using their children to display the data).

I know I'm not adding much here, but the lights came on for me, and maybe this comment will help someone else.

David Krider