Friday, December 18, 2009

checkbox

the model Log has a attribute :status which can be either true(valid) or false (invalid).

the view(edit.html.erb) has a form to show this model, want to use a checkbox to allow user to invalidate the log:
to populate the log's status to the check box:
if log's status is valid, the check box is not checked;
if log's status is invalid, the check box is checked;

to populate the check box's value back to log's status:
if user check the check box, the log's status will be set to false(invalid)
once the check box is checked, user is not allowed to uncheck it.

To Populate from Model to View
The tricky thing here is, the status of the check box is opposite to the log's status, so tried the following ways:
<%= f.label 'Invalide?' %><%= f.check_box !(:status)%>
or 
<%= f.label 'Invalide?' %><%= f.check_box (:status ? 0:1)%>
those wont' work, it complained either 'undefined method 'false' or undefined 0.

read the API again and googled around (kudos to rob-twf's reply at ruby on rails forum), here is the solution:
<%= f.label 'Invalide?' %><%= f.check_box :status, {:checked => !f.object.status} %>

follow the API:
check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0") 
object_name: here is our Log model,
method: here is our :status attribute, it has nothing to do with the checkbox's status(checked or not), that's what confused me in the first place
options: html options, here is the place to specify the checkbox's status, checked or not
checked_value & unchecked_value: can safely ignore them in this case.

so in order to set the checkbox checked, we defined the condition in options as:
{:checked => :status ? 0:1}
if log's status is true, uncheck the checkbox, otherwise, check it.

To Populate from View to Model
after the modification from above, we can populate the log.status value correctly to the view(edit.html.erb). then we checked the checkbox to invalidate the log and click Update button, it shows 'Log was successfully updated', however if we go to the database we can see the status is still valid(1). what is wrong?

go to the script/server screen, we found the following statements for the Update click:
Processing LogsController#update (for 127.0.0.1 at 2009-12-18 13:28:43) [PUT]
  Parameters: {"commit"=>"Update", "authenticity_token"=>"dQ3IIa6mI0IrJORrayVQjQa6RHn95AqfVvDahBglGMc=", 
"log"=>{"serial_number"=>"L-000099", "log"=>"Two zipper teeth are missing", "part_number_id"=>"4", 
"status"=>"1", "user"=>"Tom"}, "id"=>"3"}
  Log Columns (1.2ms)   SHOW FIELDS FROM `logs`
  Log Load (0.1ms)   SELECT * FROM `logs` WHERE (`logs`.`id` = 3) 
  SQL (0.1ms)   BEGIN
  SQL (0.1ms)   COMMIT
Redirected to http://localhost:3000/logs/3
Completed in 16ms (DB: 2) | 302 Found [http://localhost/logs/3]
  SQL (0.1ms)   SET NAMES 'utf8'
  SQL (0.1ms)   SET SQL_AUTO_IS_NULL=0
see there is no SQL statements between the BEGIN and COMMIT, the reason is nothing is changed for that log record, so no update to it.

How could that be possible? I just checked the check box to invalidate the log's status, the 'status' should be set to 0. well, go back to read the API further:
check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0") 
By default, if the the check box is checked, it's set to 1, otherwise, set to 0. that's the opposite to what I need here. so go back to edit.html.erb and update the code again:
<%= f.label 'Invalide?' %>
<%= f.check_box :status, {:checked => :status ? 0:1}, checked_value = "0", unchecked_value = "1" %>
now it's happy. without anymore change to the code, it can update the Log correctly.

No comments: