Rails3 Update Boolean Checkbox from Index View
I'm building a simple tasks application for our company as part of an ordering system.
I have a list of tasks with a number of rules. Nothing complex... What I'm stuck on is the addition of a checkbox to complete the task. I want it done live, from the index view without having to hit submit..
Am really not sure even where to look. I figure I need to use ajax to do this - can anyone recommend a tutorial or tell me what I should be looking for.
Have also thought about a plugin, like the edit in place ones out there.
Thanks in advance
--- EDIT 1 --
Following advice from @pcg79 below, I've added the following to my application but am not understanding how I go out actually changing the status.
In my index view I have this:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(@task) } %><
I've added the following to my application.js (added a # to get it to call properly)
$('#complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
For lack of understanding, I added this to my tasks controller:
def completed
@task = Task.find(params[:id])
@task.status = true
end
Which seemed reasonable but wasn't sure how to actually call that in the ajax?
In my development log I can see it sort of working but it says this:
ActionController::RoutingError (No route matches "/tasks"):
-- EDIT 2 --
As per advice from @jdc below, I've tried adding the following to routes.rb:
get 'tasks/:id/completed' => 'tasks#completed', :as => :completed_task
But still get the RoutingError.
-- Slight Update --
Following the excellent advise from @pcg79 below, I've updated my files with the following.
Routes.rb
get 'task/:id' => 'tasks#completed', :as => :completed_task
Index.html.erb
<td><%= check_box_tag 'complete_task_1', '', false, { 'data-href' => completed_task_path(:id => task.id) } %></td>
Tasks controller
def completed
@task = Task.find(params[:id])
@task.status = true
@task.save
end
I get no errors in my browser, but my development log shows this:
ActionController::RoutingError (No route matches "/tasks"):
For a simple checkbox, this is hard work!!!
-- Another update --
Having played all day, I decided to see what would happen with a button_to instead, forgetting the ajax side of things. I put this in my code:
<%= button_to "Complete", completed_task_path(task.id) %>
And changed routes to:
match 'tasks/:id/completed' => 'tasks#co开发者_如何学运维mpleted', :as => :completed_task
Which worked a treat. Changing back to check_box_tag breaks it all again :(
Pretty much worked out it's the contents of my function. Having removed some code, I can update the css for a #:
$('#complete_task_1').click(function() {
$.ajax({
success: function(data, textStatus, jqXHR) {
$('#thing').css("color","red");
}
});
});
Any idea what I'd need to call my action?? J
If I understand what you're looking for (when the checkbox is checked or unchecked an Ajax request is sent to the server and the associated object is saved with the result of the checkbox), then yes you'll want to do it in Ajax.
With Rails 3 you're probably using jQuery (or, IMO, you should be). You'll need to implement a click event on the checkbox element. That click event, when it's fired, will do an Ajax call to your server. You'll want to do a PUT request since it's an update. You'll send the id of the object and the value of the checkbox.
There are a decent amount of sites that have examples of Rails and Ajax. This one (http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3/) is good as it has you use the HTML 5 "data" fields which I like. There's also a bunch of similar questions here on SO. Here's one that's not Rails but will give you an idea of how to write the jQuery (AJAX Checkboxes).
Edit to answer question in comment
The checkbox can be wherever you want it since you're doing Ajax. If you want it on your index view, that's where you put it. Your checkbox will look something like this (please understand I'm not double checking my syntax or anything):
= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(@task_1) }
Then your jQuery will look something like:
$('complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
Second edit: I realized I forgot to actually send the value of the checkbox in the Ajax. You can do that and just call @task.update_attributes
or you can make the url a specific method that only completes tasks.
Edit for updated question:
To explain my second edit, in order to update the task to be completed, you can do one of two things. You can either call a method that is expressly for setting the status
attribute. Or you can call your normal, RESTful update
method passing in :task => {:status => true}
and call @task.update_attributes(params[:task])
. You've chosen to do the former which, IMO, is fine.
So you have two problems. The first is that you aren't referencing the new route which points to your completed
method. The second is that you aren't saving your object in the completed
method.
To fix the first problem, you need to change the path your data-href
attribute in the check_box_tag
method points to. You don't want task_path
. IIRC, you'll want completed_task_path(@task)
. The easiest way to find out the name of the path is to run rake routes
in your Rails project's root directory.
To fix the second problem, just make sure to call @task.save
at the end.
def completed
@task = Task.find(params[:id])
@task.status = true
@task.save
end
In your updated example, try replacing:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(@task) } %>
with:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(@task) } %>
Provided @task.id = 1
, tasks_path(@task)
returns /tasks.1
, while task_path(@task)
returns /tasks/1
精彩评论