Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using acts_as_list with has_many :through in rails

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?

like image 487
CJ F Avatar asked Mar 20 '09 02:03

CJ F


3 Answers

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

like image 145
CJ F Avatar answered Nov 19 '22 00:11

CJ F


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.

like image 30
David Krider Avatar answered Nov 18 '22 23:11

David Krider


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.

like image 44
Ian Terrell Avatar answered Nov 18 '22 23:11

Ian Terrell