Reputation: 3500
I am new to rails and trying to achieve a simple task. I want to toggle a boolean attribute "done" on an image click. In my view, my link looks like:
<%= link_to image_tag("done.png"),
feed_item,
:controller => :calendars, :action=>:toggle_done,:id=> feed_item.id,
:title => "Mark as done", :remote=> true, :class=>"delete-icon" %>
I added a route as follows:
resources :calendars do
get 'toggle_done', :on => :member
end
in the controller, I have created a method:
def toggle_done
@calendar = Calendar.find(params[:id])
toggle = !@calendar.done
@calendar.update_attributes(:done => toggle)
respond_to do |format|
flash[:success] = "Calendar updated"
format.html { redirect_to root_path }
format.js
end
When I click on the image, nothing happens I see the following error:
Started GET "/toggle_done" for 127.0.0.1 at 2010-12-27 13:56:38 +0530
ActionController::RoutingError (No route matches "/toggle_done"):
I am sure there is something very trivial I am missing here.
Upvotes: 3
Views: 5685
Reputation: 13433
Just FYI, ActiveRecord provides "toggle" and "toggle!" methods to do exactly as the name claims on a given attribute.
Route ->
resources :calendars do
member do
put :toggle_done
end
end
View (ensure you're using the correct route path and the correct HTTP Verb). GET should not be used for changing the database as per RESTful architecture. ->
<%= link_to image_tag("done.png"), feed_item, toggle_done_calendars_path(feed_item)
:title => "Mark as done", :remote=> true, :class=>"delete-icon", :method => :put %>
Controller ->
def toggle_done
@calendar = Calendar.find(params[:id])
@calendar.toggle!(:done)
respond_to do |format|
flash[:success] = "Calendar updated"
format.html { redirect_to root_path }
format.js
end
end
Upvotes: 8
Reputation: 2267
Some quick steps to fix your problem is to move the :controller and :action out of the link_to method and into the route, and fix your route.
Your route is inside the block for resource :calendars. Every route in there will match on the /calendars/ path, so this route won't match /toggle_done. Here's a simple route that will match and route /toggle_done to :controller => :calendars, :action => :toggle_done
match :toggle_done => "calendars#toggle_done"
Having said that, I would suggest going with a RESTful route. I'm guessing you have calendar resources, which have many feed_items, and I'm guessing the toggle_done action updates the done boolean on one of these feed_items. An update should be mapped as a PUT request.
resources :calendars do
resources :feed_items do
put :toggle_done, :on => member
end
end
This will give you a route for /calendars/1/feed_items/2/toggle_done, to toggle done on feed_item 2 in calendar 1.
Upvotes: 0
Reputation: 28934
When using link_to
, you can specify the URL by passing either an Active Record model with an associated resource, or by passing regular :controller
/:action
arguments. Now you're passing both an Active Record model (feed_item
) and :controller
/:action
arguments, but you only should pass :controller
/:action
arguments in this case.
Also, when you pass both a URL hash and additional HTML arguments you need to include the brackets around the two hashes in order to distinguish between them.
Thus, try the following:
<%= link_to image_tag("done.png"),
{ :controller => :calendars, :action =>:toggle_done, :id => feed_item.id },
{ :title => "Mark as done", :remote => true, :class =>"delete-icon" } %>
Upvotes: 2