Update Multiple Boolean Attributes in Rails3
We are hosting an event where students need to submit two pieces of paper and pay to attend. The model I’ve created has three boolean values for these three items: safety_waiver, image_waiver and paid. As the forms and payments come in, I could manually edit each entry and check off who has paid or not. But, since I’ve done a few of these events in the past, I know it would be easier if I could just see a list of everyone who hasn’t paid or turned in their waivers and check a bunch at once. I tried following Railscast #52, which was great and almost got me there, but didn’t work for me in the end. So here’s what I did.
Students#index
<%= form_tag marked_students_path, :method => :put do %> <% @students.each do |student| %><%= link_to "#{student.fullname}", student %> <%= check_box_tag "safety_waiver_ids[]", student.id, student.safety_waiver %> <%= check_box_tag "image_waiver_ids[]", student.id, student.image_waiver %> <%= check_box_tag "image_paid_ids[]", student.id, student.paid %> <% end %> </pre> <%= submit_tag 'Update' %> Note that above, the third check_box_tag option sets the value of the tag. So, if paid is already true, the box will already be checked. This seemed fine, but in my controller below, I’m not checking if a box is unchecked, just those that have been checked. After thinking about it for a while, I know that unchecking something is a pretty rare occurrence. However, I could see that since there will be over 150 entries in this table, that I might accidentally uncheck something when I meant to check a box on another line. So I decided to change how things are displayed. If one of those booleans is already true, it doesn’t show a box, but will say ‘Yes’ there instead. So I’m unable to uncheck boxes accidentally. If I do need to uncheck something, I’ll have to go in an edit that individual entry, which is fine because it’s very rare to uncheck.
This means that my view has some if statements to see if the value of the booleans is already true. I’ll just show one section here, but there would be one of these for each of the three booleans.
<% if student.safety_waiver %> <%= student.safety_waiver? %> <% else %> <%= check_box_tag "safety_waiver_ids[]", student.id %> <% end %>students_controller
def marked @students = Student.where(:id => params[:safety_waiver_ids]) @students.update_all(:safety_waiver => true) @students = Student.where(:id => params[:image_waiver_ids]) @students.update_all(:image_waiver => true) @students = Student.where(:id => params[:paid_ids]) @students.update_all(:paid => true) redirect_to students_url endIn the railscast, the command to use was
Student.update_all(:safety_waiver => true, :id => params[:safety_waiver_ids])But this didn’t work for me. I kept getting an SQL error:
ERROR 1062 (23000): Duplicate entry '7' for key 'PRIMARY'because the sql that was running was:
update students set safety_waiver=1, id=7;when the command that it needed to run should have been:
update students set safety_waiver=1 where id=7I didn’t know how to make that change, so I just did as shown in the marked method above.
routes.rb
resources :students do put 'marked', on => :collection endThat pretty much does it.