问题
Following the Railscasts episode about sortable lists (http://railscasts.com/episodes/147-sortable-lists-revised?view=asciicast), I've got everything in place, however instead of doing sorting on the model whose #show action is displaying the list, it's a nested model.
My site is for managing a very complex fantasy football league. One of the aspects of the league is that GMs have a yearly salary cap amount, players have a value, and players can be signed to multi-year contracts.
Anyway, I'm creating a draft roster list that lets you add players and keep track of the ones you want to try and draft. I want this list to be sortable. I have it setup using a has_many :through relationship.
Here are the three models:
class DraftRoster < ActiveRecord::Base
attr_accessible :name, :team_id
belongs_to :team
has_many :roster_spots
has_many :players, through: :roster_spots
...
end
Then:
class RosterSpot < ActiveRecord::Base
attr_accessible :draft_roster_id, :player_id, :position
belongs_to :draft_roster
belongs_to :player
acts_as_list
end
And finally (this has a LOT more code removed here as its not applicable to this issue):
class Player < ActiveRecord::Base
attr_accessible :auction_value, :first_name, :last_name, :nfl_team, :position, :is_drafted, :is_bought_out, :is_extended, :is_franchised, :bye_week, :full_name, :contracts_attributes, :subcontracts_attributes
...
has_many :roster_spots
has_many :draft_rosters, through: :roster_spots
...
end
So I've gone through and I've follow the Railscasts episode exactly. My #sort action is in the roster_spots_controller.rb file (and the position attribute is also on this model).
draft_rosters_controller.rb
def sort
params[:roster_spot].each_with_index do |id, index|
RosterSpot.update_all({ position: index + 1 }, { id: id })
end
render nothing: true
end
And I have the necessary route:
resources :roster_spots do
collection { post :sort }
end
The Coffeescript:
jQuery ->
$('#draft-roster-players').sortable(
axis: 'y'
handle: '.handle'
update: ->
$.post($(this).data('update-url'), $(this).sortable('serialize'))
)
The draft_rosters#show action:
def show
@draft_roster = DraftRoster.find(params[:id])
@team = @draft_roster.team
@players = @draft_roster.players.order("position")
respond_to do |format|
format.html # show.html.erb
format.json { render json: @draft_roster }
end
end
And finally, the view:
<ul id="draft-roster-players" data-update-url="<%= sort_roster_spots_url %>">
<% @players.each do |player| %>
<%= content_tag_for :li, player do %>
<span class="handle">[drag]</span>
<%= link_to h(player.full_name), player %>
<% end %>
<% end %>
</ul>
Everything is dragging and dropping as expected, but when I drop a player into a new spot on the list, in the Chrome JavaScript console, I keep getting this error:
POST http://localhost:3000/roster_spots/sort 500 (Internal Server Error)
send
x.extend.ajax
x.(anonymous function)
$.sortable.update
$.Widget._trigger
$.widget._trigger
(anonymous function)
(anonymous function)
$.widget._clear
(anonymous function)
$.widget._mouseStop
(anonymous function)
$.widget._mouseUp
(anonymous function)
_mouseUpDelegate
x.event.dispatch
v.handle
I don't get it. The only thing I can think of is that it somehow has to do with the nested resources, but I don't see why that would matter necessarily. A few comments on the Railscasts episode alluded to having some issues with nested resources, but none of them provided the solution they used to get it working and they're from years ago.
Has anyone done sortable lists through jQuery in a Rails 3.2 app? What's the trick necessary to get it working? I've tried passing a few variables to the data-update-url attribute on the tag but nothing has worked.
Any help would be appreciated!
UPDATE Stupidly, I never checked the Rails console output...I'm getting this error:
NoMethodError (undefined method `each_with_index' for nil:NilClass):
app/controllers/roster_spots_controller.rb:89:in `sort'
回答1:
Figured it out looking at the console output! I had to make the following changes:
draft_rosters#show view:
<ul id="draft-roster-players" data-update-url="<%= sort_roster_spots_url %>">
<% @roster_spots.each do |roster_spot| %>
<%= content_tag_for :li, roster_spot do %>
<span class="handle">[drag]</span>
<%= link_to h(roster_spot.player.full_name), roster_spot %>
<% end %>
<% end %>
</ul>
draft_rosters#show action:
def show
@draft_roster = DraftRoster.find(params[:id])
@team = @draft_roster.team
@roster_spots = @draft_roster.roster_spots.order("position")
respond_to do |format|
format.html # show.html.erb
format.json { render json: @draft_roster }
end
end
roster_spots_controller.rb
def sort
params[:roster_spot].each_with_index do |id, index|
RosterSpot.update_all({ position: index + 1 }, { id: id })
end
render nothing: true
end
And now it's working as it should be. :) I hope that this can be of help to others should they find themselves in this situation.
来源:https://stackoverflow.com/questions/22884753/rails-3-2-jquery-sortable-list-500-error-with-nested-resources