Hi,
I’m having a very strange problem using a AJAX sortable list
containing images for articles. I tried a lot of things and searched
for hours but I don’t find the reason. I would really appreciate your
help. Please excuse my deficient english, I’m from Berlin. I try to
explain the situation as clear as possible. If you need any further
info, just drop a note.
The idea:
User can post articles and add comments and images (assets) to each
article. So every article has many comments and assets. I’m using
restful routing and AJAX for image uploading, deleting and adding
comments etc. without any problems.
The problem:
When I try to reorder the images, all the information is saved, but
then the index action of the controller is called again. So the page
reloads. But I’m using Ajax to prevent this. If I have for example a
form on the page with unsaved information, all user input is lost and
the page is refreshed with the data from the DB.
The Routing:
To access the assets of an article (e.g. ID 3) I call /articles/3/
assets .
My routes.rb looks like this (partial):
map.resources :articles, :member => {:publish => :get} do |article|
article.resources :comments do |comment|
comment.resources :comments
end
article.resources :assets, :collection => {:saveorder => :post}
end
rake routes shows me for the articles the following routes:
articles GET /
articles
{:action=>“index”, :controller=>“articles”}
formatted_articles GET /
articles.:format
{:action=>“index”, :controller=>“articles”}
POST /
articles
{:action=>“create”, :controller=>“articles”}
POST /
articles.:format
{:action=>“create”, :controller=>“articles”}
new_article GET /articles/
new
{:action=>“new”, :controller=>“articles”}
formatted_new_article GET /articles/
new.:format
{:action=>“new”, :controller=>“articles”}
edit_article GET /articles/:id/
edit
{:action=>“edit”, :controller=>“articles”}
formatted_edit_article GET /articles/:id/
edit.:format
{:action=>“edit”, :controller=>“articles”}
publish_article GET /articles/:id/
publish
{:action=>“publish”, :controller=>“articles”}
formatted_publish_article GET /articles/:id/
publish.:format
{:action=>“publish”, :controller=>“articles”}
article GET /
articles/:id
{:action=>“show”, :controller=>“articles”}
formatted_article GET /
articles/:id.:format
{:action=>“show”, :controller=>“articles”}
PUT /
articles/:id
{:action=>“update”, :controller=>“articles”}
PUT /
articles/:id.:format
{:action=>“update”, :controller=>“articles”}
DELETE /
articles/:id
{:action=>“destroy”, :controller=>“articles”}
DELETE /
articles/:id.:format
{:action=>“destroy”, :controller=>“articles”}
article_comments GET /articles/:article_id/
comments
{:action=>“index”, :controller=>“comments”}
formatted_article_comments GET /articles/:article_id/
comments.:format
{:action=>“index”, :controller=>“comments”}
POST /articles/:article_id/
comments
{:action=>“create”, :controller=>“comments”}
POST /articles/:article_id/
comments.:format
{:action=>“create”, :controller=>“comments”}
new_article_comment GET /articles/:article_id/
comments/new
{:action=>“new”, :controller=>“comments”}
formatted_new_article_comment GET /articles/:article_id/
comments/new.:format
{:action=>“new”, :controller=>“comments”}
edit_article_comment GET /articles/:article_id/
comments/:id/edit
{:action=>“edit”, :controller=>“comments”}
formatted_edit_article_comment GET /articles/:article_id/
comments/:id/edit.:format
{:action=>“edit”, :controller=>“comments”}
article_comment GET /articles/:article_id/
comments/:id
{:action=>“show”, :controller=>“comments”}
formatted_article_comment GET /articles/:article_id/
comments/:id.:format
{:action=>“show”, :controller=>“comments”}
PUT /articles/:article_id/
comments/:id
{:action=>“update”, :controller=>“comments”}
PUT /articles/:article_id/
comments/:id.:format
{:action=>“update”, :controller=>“comments”}
DELETE /articles/:article_id/
comments/:id
{:action=>“destroy”, :controller=>“comments”}
DELETE /articles/:article_id/
comments/:id.:format
{:action=>“destroy”, :controller=>“comments”}
article_comment_comments GET /articles/:article_id/
comments/:comment_id/comments
{:action=>“index”, :controller=>“comments”}
formatted_article_comment_comments GET /articles/:article_id/
comments/:comment_id/comments.:format
{:action=>“index”, :controller=>“comments”}
POST /articles/:article_id/
comments/:comment_id/comments
{:action=>“create”, :controller=>“comments”}
POST /articles/:article_id/
comments/:comment_id/comments.:format
{:action=>“create”, :controller=>“comments”}
new_article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/new
{:action=>“new”, :controller=>“comments”}
formatted_new_article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/new.:format
{:action=>“new”, :controller=>“comments”}
edit_article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/:id/edit
{:action=>“edit”, :controller=>“comments”}
formatted_edit_article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/:id/edit.:format
{:action=>“edit”, :controller=>“comments”}
article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/:id
{:action=>“show”, :controller=>“comments”}
formatted_article_comment_comment GET /articles/:article_id/
comments/:comment_id/comments/:id.:format
{:action=>“show”, :controller=>“comments”}
PUT /articles/:article_id/
comments/:comment_id/comments/:id
{:action=>“update”, :controller=>“comments”}
PUT /articles/:article_id/
comments/:comment_id/comments/:id.:format
{:action=>“update”, :controller=>“comments”}
DELETE /articles/:article_id/
comments/:comment_id/comments/:id
{:action=>“destroy”, :controller=>“comments”}
DELETE /articles/:article_id/
comments/:comment_id/comments/:id.:format
{:action=>“destroy”, :controller=>“comments”}
saveorder_article_assets POST /articles/:article_id/
assets/saveorder
{:action=>“saveorder”, :controller=>“assets”}
formatted_saveorder_article_assets POST /articles/:article_id/
assets/saveorder.:format
{:action=>“saveorder”, :controller=>“assets”}
article_assets GET /articles/:article_id/
assets
{:action=>“index”, :controller=>“assets”}
formatted_article_assets GET /articles/:article_id/
assets.:format
{:action=>“index”, :controller=>“assets”}
POST /articles/:article_id/
assets
{:action=>“create”, :controller=>“assets”}
POST /articles/:article_id/
assets.:format
{:action=>“create”, :controller=>“assets”}
new_article_asset GET /articles/:article_id/
assets/new
{:action=>“new”, :controller=>“assets”}
formatted_new_article_asset GET /articles/:article_id/
assets/new.:format
{:action=>“new”, :controller=>“assets”}
edit_article_asset GET /articles/:article_id/
assets/:id/edit
{:action=>“edit”, :controller=>“assets”}
formatted_edit_article_asset GET /articles/:article_id/
assets/:id/edit.:format
{:action=>“edit”, :controller=>“assets”}
article_asset GET /articles/:article_id/
assets/:id
{:action=>“show”, :controller=>“assets”}
formatted_article_asset GET /articles/:article_id/
assets/:id.:format
{:action=>“show”, :controller=>“assets”}
PUT /articles/:article_id/
assets/:id
{:action=>“update”, :controller=>“assets”}
PUT /articles/:article_id/
assets/:id.:format
{:action=>“update”, :controller=>“assets”}
DELETE /articles/:article_id/
assets/:id
{:action=>“destroy”, :controller=>“assets”}
DELETE /articles/:article_id/
assets/:id.:format
{:action=>“destroy”, :controller=>“assets”}
Please note that I’m using acts_as_tree for the comments to enable
replys.
My Controller:
class AssetsController < ApplicationController
make_resourceful do
actions :show, :new, :edit, :update, :destroy
belongs_to :article
before :new do
@comment.user = current_user
end
end
def index
if params[:article_id].nil?
@assets = Asset.find(:all, :conditions => {:parent_id =>
nil}, :order => ‘order_number ASC’)
else
@assets = Asset.find(:all, :conditions => {:parent_id =>
nil, :article_id => params[:article_id]}, :order => ‘order_number
ASC’)
end
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @assets.to_xml }
format.js
end
end
This is the action which is called by sortable_element
def saveorder
params[:assetlist].each_with_index do |id, position|
asset = Asset.find(id)
asset.update_attribute(‘order_number’, position)
end
respond_to do |format|
format.js {render :nothing => true}
end
end
end
My views (I’m using partials and HAML):
First the index.haml
%h1= _(“Listing assets”)
%ul#assetlist
=render :partial => @assets
=render :partial => ‘form’
=sortable_element(“assetlist”, :url => saveorder_article_assets_path)
Than the _asset.haml partial
%li{:id => “asset_#{asset.id}”}
= link_to(image_tag(asset.public_filename(:thumb))) if asset.image?
= link_to(asset.filename, article_assets_path(asset))
= link_to_remote _(“Delete”), :url =>
article_assets_path(asset), :confirm => _(‘Are you sure?’), :method
=> :delete
the form partial is just for uploading and works perfectly well, so
I guess it’s not interesting here
And last but not least the Mongrel Server output in the console.
Please note that after the action saveorder the index action is called
again → the problem.
#######
Processing AssetsController#saveorder (for 127.0.0.1 at 2008-06-18
23:21:16) [POST]
Session ID:
BAh7BzoMY3NyZl9pZCIlODg2OTc0MmE3ZDFjN2RiNTQxM2Y0ZWQ3ODIyNDVl
%0AMDMiCmZsYXNoSUM6J0FjdGlvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhh
%0Ac2h7AAY6CkB1c2VkewA%3D–985a32d778e836c3c207d7b757c6171368ecfe0a
Parameters: {“action”=>“saveorder”,
“authenticity_token”=>“8ecfdb4a14b7c399089e0aaeb5db011ce09712c2”,
“controller”=>“assets”, “assetlist”=>[“238”, “234”],
“article_id”=>“1”}
Asset Columns (0.002068) SHOW FIELDS FROM assets
Asset Load (0.001336) SELECT * FROM assets
WHERE (assets
.id
= 238)
SQL (0.000160) BEGIN
Asset Update (0.001113) UPDATE assets
SET created_at
=
‘2008-06-16 20:14:04’, thumbnail
= NULL, content_type
= ‘image/
jpeg’, user_id
= 25, order_number
= 0, height
= 2048, filename
= ‘DSC00005.JPG’, width
= 1536, parent_id
= NULL, updated_at
=
‘2008-06-18 23:21:16’, size
= 641111, article_id
= 1 WHERE id
=
238
SQL (0.000518) COMMIT
Asset Load (0.000278) SELECT * FROM assets
WHERE (assets
.id
= 234)
SQL (0.000146) BEGIN
Asset Update (0.000432) UPDATE assets
SET created_at
=
‘2008-06-16 00:57:52’, thumbnail
= NULL, content_type
= ‘image/
jpeg’, user_id
= 25, order_number
= 1, height
= 1536, filename
= ‘DSC00008.JPG’, width
= 2048, parent_id
= NULL, updated_at
=
‘2008-06-18 23:21:16’, size
= 789570, article_id
= 1 WHERE id
=
234
SQL (0.000492) COMMIT
Completed in 0.03366 (29 reqs/sec) | Rendering: 0.00008 (0%) | DB:
0.00654 (19%) | 200 OK [http://0.0.0.0/articles/1/assets/saveorder]
Processing AssetsController#index (for 127.0.0.1 at 2008-06-18
23:21:16) [GET]
Session ID:
BAh7BzoMY3NyZl9pZCIlODg2OTc0MmE3ZDFjN2RiNTQxM2Y0ZWQ3ODIyNDVl
%0AMDMiCmZsYXNoSUM6J0FjdGlvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhh
%0Ac2h7AAY6CkB1c2VkewA%3D–985a32d778e836c3c207d7b757c6171368ecfe0a
Parameters: {“action”=>“index”, “controller”=>“assets”,
“article_id”=>“1”}
Asset Load (0.000625) SELECT * FROM assets
WHERE
(assets
.parent_id
IS NULL AND assets
.article_id
= ‘1’) ORDER
BY order_number ASC
Rendering template within layouts/application
Rendering assets/index
Asset Columns (0.001937) SHOW FIELDS FROM assets
Rendered assets/_asset (0.00773)
Rendered assets/_asset (0.00256)
Rendered assets/_form (0.00238)
Completed in 0.03758 (26 reqs/sec) | Rendering: 0.01914 (50%) | DB:
0.00256 (6%) | 200 OK [http://0.0.0.0/articles/1/assets]
I also tried to find the error using firebug and it shows an error in
the XMLHttpRequest, but as soon as the index is refreshed the console
is cleared and I don’t get the message.
Any hint or idea is welcome. Please help me here, I’m completely
stuck!
Thanks.