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 %>
<%= submit_tag 'Update' %>
<% end %>

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
 end

In 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=7

I 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
end

That pretty much does it.

A Bad Habit

Until yesterday, I had been carless for the past few weeks. Even though it was ridiculously cold, if I wanted to get to work, I'd do my bus-el-bus trip to get there and then reverse it to get home. In all honesty, this wasn't that difficult, though it was rather cold this week. One of the things that I had thought about, when I bought my house, was that I didn't want to be dependent on a car. So, I can take public transit to work, I can walk to a grocery store or other stores that I might need. Now though, that I have my car back, I was just thinking that I'll drive over to Target this morning to pick up some stuff. This is ridiculous. Last week, I would have (and did) just walk there. There was a talk in the evening the other day downtown that I wanted to hear. So, even after I took public transit home, ate dinner and was a bit tired, I bundled up again and walked to a different el stop to take the train to go to the meeting. Now, I'm being a total weenie and want to drive to a store that's maybe a mile away, but probably less to buy some things that aren't even heavy. I am completely ashamed of myself. This is a habit that I need to break and I'm not sure how I'll do it. But, I'm going to try and be more aware of when I instinctively think to just get in my car and drive. More immediately, I'm going to put on my boots and coat and walk over to the store. Self, quit being such a wuss!

FUN!

My brother convinced me to buy a mountain bike on Friday and we went up to Kettle Moraine on Saturday for a ride. I was a bit nervous, hoping that I wouldn't hurt myself, since I'd never done anything like this. I love riding my bike, but I usually stay on pavement, which makes the riding pretty easy, even in traffic. Since there were a few of us who had never done it before, we went on an intermediate trail of about 4 miles. It was about 41 degrees, which wasn't bad, but it was totally muddy. And I have to be honest, I haven't gotten that filthy in a long time and it was fun. Since it was so muddy and a bit chilly, I couldn't take too many pictures because it was a pain to take off my gloves and get the camera out. But here are a few shots from the day.

Getting ready with our brand-new bikes.
Getting ready with our brand-new bikes.
Our bikes are no longer classified as new.
Our bikes are no longer classified as new.
The end of the trail.  Going up hills with the trail like this was hilarious.
The end of the trail. Going up hills with the trail like this was hilarious.
That's me!
That's me!
Sevi needed a rear fender.
Sevi needed a rear fender.
The muddy bikes ready to go home to get hosed off.
The muddy bikes ready to go home to get hosed off.

I also downloaded an app to see if we could map our ride, because that sounded pretty cool. Here's what MapMyRide says we did.

Screen Shot 2013-01-21 at 9.10.43 AM

I was just an hour, but I think that was perfect for my first time trying it.

Rails and Autocomplete

I recently wrote a simple rails app to let people record measurements (current and voltage) on for a given plate. Each plate can have many measurements and each measurement belongs to only one plate. I wanted to make it easy for people to enter the data and there might be a fair number of plates, so I didn't want people to have to scroll down a long drop down menu to pick a plate. This seemed like an ideal situation to use autocomplete on. Basically, the home screen is just the new measurements path. So, putting in the measurements will be easy. I then wanted to have a text field for the plate name that has autocomplete enabled. As the user enters in information for each plate, a little drop down list will popup that users can use to pick the correct plate. And if it's a new plate, it will automatically add it to the database.

I had avoided doing something like this for a long time because I knew it would require javascript and I know absolutely none. However, I recently subscribed to Railscasts and watched an episode on autocomplete (#102). It didn't look too difficult and I gave it a try.

app/assets/javascripts/application.js

jQuery ->
    $('#measurement_plate_name').autocomplete
        source: $('#measurement_plate_name').data('autocomplete-source')

Note that coffeescript IS whitespace dependent. Not knowing that probably caused the most difficulty in the entire process. Each one of those tabs above are four spaces. I usually use tabs that are two spaces and it didn't work.

app/models/measurement.rb

belongs_to :plate

attr_accessible :current, :voltage, :note, :plate_name
def plate_name
  plate.try(:name)
end

def plate_name=(name)
  self.plate = Plate.find_or_create_by_name(name) if name.present?
end

I'm creating a virtual attribute to use in the form to set the plate name.

app/views/measurements/new.html.erb

<%= form_for (@measurement), :url => create_measurement_path, :method => :post do |f| %>
  

<%= f.label :plate_name %> <%= f.text_field :plate_name, data: {autocomplete_source: Plate.order(:name).map(&:name)} %>

<%= f.label :current %> <%= f.text_field :current %>

<%= f.label :voltage %> <%= f.text_field :voltage %>

<%= f.label :note %>
<%= f.text_area :note, size: '30x5' %>

<%= f.submit 'Submit' %>

<% end %>

I deleted some extra stuff in my form (error checking, etc.) because this is the important stuff that needs to be there.

app/assets/stylesheets/measurements.css.scss

ul.ui-autocomplete {
  position: absolute;
  list-style: none;
  margin: 0;
  padding: 0;
  border: solid 1px #999;
  cursor: default;
  li {
    background-color: #FFF;
    border-top: solid 1px #DDD;
    margin: 0;
    padding: 0;
    a {
      color: #000;
      display: block;
      padding: 13px;
    }
    a.ui-state-hover, a.ui-state-active, a.ui-state-focus {
      background-color: #FFFCB2;
    }
  }
} 

I had a hard time getting highlighting to work on the drop down list that appears. I had to add the a.ui-state-focus (line 18) to the css given in the Railscast to get it to work. I would have posted that on the site, but you have to log in with a github account and it just seemed like a hassle.

That's basically it.

Coffeescript is Whitespace Sensitive

I'm attempting to get autocomplete working on a rails app. I'm basically following the instructions in Railscast #102 (revised). It wasn't working because I didn't realize that coffeescript was whitespace sensitive. Once I realized that, I thought I was set, but I wasn't. I like having my tabs be two spaces, but coffeescript wants four space tabs. So after I doubled all of my tabs, things started working.

jQuery ->
    $('#measurement_plate_name').autocomplete
        source: $('#measurement_plate_name').data('autocomplete-source')

Context

There are a number of blogs that I read, almost daily. I know a lot of people do this and many do it by subscribing to the RSS feed of a given blog. I am not one of those people. Why? I like to see the information in its original context. RSS readers strip everything off the webpage except the text of the post. So just by glance, I can't tell which website the post came from. I don't like this at all. I prefer to read the text on the original site that the author created. Why? It helps me to remember where I read the information. A typical example, just the other day, I was thinking that there was a book I was interested in reading because I had read about it on some website. It was a somewhat technical book, so it could have been reviewed on any number of sites that I visit. However, I couldn't remember the title and I didn't think it was an actual review of the book. I was something written by the person who wrote the book. I remembered liking the post, but all I could remember was that I had read about it in December and it was to be published in January. Now that it was January, I wanted to remember it to see if I wanted to buy it. After picturing the article, I remembered that it was on the NY Times website. I like that my brain still had the connection of where I read the article. I supposed if I read it in an RSS feed (which I don't even know if the NY Times provides), I could have looked there somehow. But I think it's good for my brain to still be making connections like this. It's probably more inefficient to read blogs this way, but it's my preferred way. And I'm also not a fan of making everything more efficient. Inefficiency is good. But that's a post for another day.

To 2013

Here are my goals for 2013. A lot of the same things as last year, but hopefully I'll get further along with them.

  • C Programming
    I spent some time last year, but need to be more systematic in the coming year. The number one goal is to understand the use of pointers better. Once I have that down, I think I'll be able to move on to looking to write a device driver.
  • Finish the kitchen
    This will take some time, though nearly not as long as the things I've done previously. The holdup on starting is that I want to have at least $10,000 saved up before I start. This will take me a while. In the meantime, I'm not doing anything in the kitchen because I am using it now that I'm living here again.
  • Take an overnight bike trip
    No camping, but a trip of maybe 100-200 miles or so, where I can ride and stay at motels for a day or two.
  • Electronics
    I want to finish working through the eagle tutorials. Then design a board to use with my map game. I'd like to actually finish building the map game too.
  • Book
    I'd like to write up an ebook about using a linux server to replace a windows domain. I've done it and I think it would be helpful to have all the information in a single place.
  • Bicycling
    I did a pretty good job of consistently jogging last year. I think I should mix things up and switch sports a little. So I may make a bigger effort to ride my bike more this year.
  • Ruby
    Convert a bunch of my scripts that are currently in perl to ruby to help me continue to get better at ruby.
  • Computational Geometry
    I've been getting interested in math again and recently found out about computational geometry. This seems to be pretty common in computer graphics, which I've been interested in. My math is very rusty, so I'm probably going to have to do a lot of review work before I get back into this, but I think it would be really helpful.

I'm keeping the list a little short this year, so that I can try to stay more focused.