2015 Year in Review

I'm trying to come up with a one-word summary for 2015 and am having some problems. All that pops into my mind is ok, which is sort of a lousy word to sum up a year. Perhaps acceptable would be better? Anyway, there's no need to dwell on a one-word summary. Let me look at things in a bit more detail.

  • House - Personally, I didn't do any work at all. There are still a few little things to do after finishing the kitchen last year and I didn't even think about doing them. The big (and expensive) news about the house was the new roof that I had put on in September. I knew I needed a new roof for a while. It became a much bigger deal over the summer when lots of leaks showed up. That was a ~$15k bill that I wasn't expecting, which was a bit of a hit to my finances.
  • Travel - Spent nine days in NYC with my bike, which was great. My friend Ellen came out for a visit over the summer and we took a road trip to Toronto, which was a lot of fun. And hit Detroit with Shadla and Garin for the Tour de Troit, which was cool. Didn't travel as much as in 2014, but that's ok. I probably spent as much as I did in 2014 though, as NYC was pretty expensive.
  • Work - I think this was the biggest drag on my year. I made a gigantic error at work that still makes me angry with myself when I think about it. I'm trying to forgive and forget, but it's one of those things that was just so stupid and preventable. Oh well. No one is perfect.
  • Health - I'm not entirely pleased with myself either here. I did bike a ton (more on that later), but I wasn't good about what I ate and I've screwed up my knee. Both of these were things that I had intended to improve on, but didn't.
  • Biking - This was my one bright spot of the year. In fact, I would say that 2015 was the year that I went from a person who just liked to ride her bike to one of those crazy people who think that the world would be exceptional if everyone biked more and drove less. After riding for a while, I decided that I wanted to ride at least 2,000 miles for the year. I hit that at the end of October and then decided to not look at my biking total until now. So my total for the year is (drumroll please)... 2252 miles!
    IMG_4513

Those are the general highlights off the top of my head. Let's take a look now at the resolutions that I made at the start of the year to see how I did.

  • Dining room table - Nope, didn't do it. Used Janet's plastic tables for parties again. The good news is that I gave them back to her, so I have to do something for next year.
  • Welding - Thought about it and even picked out the welder I'm going to buy. But I didn't want to spend the money.
  • Back porch - Nope, it's still a mess
  • Being active - Pretty much all I did was bike, which wasn't bad, but I should have done more varied things.
  • Health - Failed, already covered above.
  • Travel - Ok
  • Build stuff - I didn't make anything as cool as the press, but I did make myself a nice new big workbench. I also made some xmas gifts out of old wood for the cousins. I had to repair my planer a few times, so that was sort of fun. I also bought a table saw which I used quite a bit, though I'm still nervous when I use it.
  • Make a dent in the mortgage - I stuck to the plan and paid an extra $300/month. Think I'm still on schedule to pay it off in seven years, though I wish it were about half of that.
  • Hang out more with my friends - I always have room for improvement with this. Though if I didn't always see them physically, I am getting better about staying in touch.
  • Volunteer - Failed. I tried going to Open Books, but didn't enjoy it and was too lazy to try someplace else.
  • Drive less - SUCCESS! - This was without question my greatest success of the year. I will now take down my calendar and count. Here are my totals:
    Month Number of Days Drove Number of Days Didn't Use Car
    January 21 10
    February 16 12
    March 21 10
    April 13 17
    May 8 23
    June 18 12
    July 19 12
    August 16 15
    September 12 18
    October 14 17
    November 17 13
    December 19 12
    Total 194 171

    I am very pleased with this result. I don't think that I was a jerk about this, in that I did drive if it would help someone out or to do something for fun. I just tried to be conscious of when I took the car out and thought first if I could accomplish the trip by bike. And I have to say, using the calendar helped. Marking a smiley face always made me happy. I may have to start using a calendar for other habits I want to form.

    My calendar for May, my best month.
    IMG_4514

I guess the last thing to touch on would be finances. The aforementioned new roof and trip to NYC took a really big chunk of money. Though, the good news is that I can definitely say that biking more helped out with my finances. On auto-related expenses (gas, insurance, maintenance, etc.), I paid $4,462.97 in 2014. I know the price of gas was less in 2015 (but not that much less). On all those same things, in 2015, I only paid $2,743.37. So I like to think that I basically paid for my entire trip to NYC by biking more throughout the year.

Overall, not including my mortgage payments, my overall expenses for the year were $44928.81. If I also take out the home improvements, which is basically just the cost of the new roof (since that shouldn't be yearly expense), my expenses for the year were $26182.46. I've been in the $25-30k range for the past few years, so that looks good to me. I'm sure I could cut back on a few more things to reduce it more, but since I don't have to, I'm not going to worry about it.

Guess that's it for 2015. Not great, not bad...an acceptable year. Tomorrow, I'll lay out what I want to do in 2016.

Declarative Authorization attribute rules

I have a website where I use declarative authorization to determine who is allowed to do what. One thing that I need to allow is for people to change their own passwords. It's pretty simple, my model/controller is users. Here's what I needed to do:

controllers/users_controller.rb

class UsersController < ApplicationController
  filter_access_to :all
  filter_access_to :edit, :update, :attribute_check => true

config/authorization_rules.rb

role :user do
	has_permission_on [:users], to: [:edit, :update] do
		if_attribute :id => is { user.id }
	end
end

Some of my user accounts are local (where I store the password) and some are on an ldap server, where the password is stored elsewhere. I'm only allowing those people who are local to change their password. And I put the form behind a 'Profile' link that I'm showing in the navigation bar. So this is the bit I added to the view to show it only for local_accounts.

views/layouts/application.html.erb

<% if current_user.local_account %>
  
  • <%= link_to "Profile", edit_user_path(current_user.id) %>
  • <% end %>

    controllers/application_controller.rb (holds current_user method)

    def current_user_session
     return @current_user_session if defined?(@current_user_session)
      @current_user_session = UserSession.find
    end
    
    def current_user
     return @current_user if defined?(@current_user)
      @current_user = current_user_session && current_user_session.record
    end
    

    I haven't had to do this because, until recently, all of my users were being cleared off the ldap server. But now, we're having some cases where I need people not affiliated with my employer needing access to some pages.

    It’s Funny

    I'm a huge fan of YouTube for learning how to do different things. I've been watching tons of YouTube videos for woodworking while I try to build stuff with my reclaimed wood. Last weekend, I decided got a beanbag chair that had no cover. So I decided to make a new cover for it and in the process broke something on my sewing machine. So I was looking around YouTube for some help on fixing it. In the process, I watched a bunch of videos on sewing. It was so funny to me how the genders of the people hosting the videos just changed. For woodworking, I can think of one female who made videos. Everyone else was guys. For sewing, it's all women. This just struck me as very funny.

    Early Gift to Me

    Since I had been doing a bit more work in my basement, I was continually using my old workbench and it was annoying me more and more. It's more of a cheap worktable than workbench. But the big issue is that it was just really too tall for me. It was around 36" tall and I think that I'd prefer a workbench that was quite a bit lower. It really hit me when I was trying to use a handplane to clean up some old lathe. Along with being too tall, it was also too wobbly, which made planing impossible. So I found a design online that didn't look too hard. I took apart the old table and made myself a new workbench.

    Old table:
    IMG_4433

    New workbench:
    IMG_4438

    The height is definitely better on the new one. It's really only 30" tall. I'd like to say that it's incredibly sturdy, but I think it still wobbles a little. I only know this because I was trying to plane the top completely smooth. I did an ok job of screwing the top boards together, but one did stick out a little more than the others. While trying to plane it, the whole table did move around a little. Part of the problem is probably due to my handplane not being very sharp. The other is just the design. I think I might put a lower shelf on and then fill it with some old bricks I have lying around. That should give it the heft I need to make it be a good workbench. I might also buy a nice piece of mdf or plywood to put on the top so I don't have to plane or sand the whole thing completely flat.

    Making a PDF File and Automatically Attaching It

    I'm writing a rails site that collects information from an applicant and references from other people that will then be reviewed by a different group of people. For the programmer, it's easy to present the information from the database on a webpage and then provide links to uploaded documents. However, this is not necessarily the easiest way for the reviewers to read all the information. Based on other sites that do the same type of job, I've learned that reviewers want to be able to download a single file with all the information in it. I've put together various hacks in the past to do this, but have recently come up with a proper way. The following isn't complete, but it presents the basics of how to do this.

    There are three models that I'm using.
    1. Applicant - This is where the applicant initially fills out all of their info and uploads a CV.
    2. Reference_Document - We require each applicant to give us the names of two people who will write references for them. These uploaded documents are stored in reference_document. Each applicant has_many reference_documents.
    3. Application - This is the single model that just has an uploaded file that is a pdf created by combining the applicant's info, CV and any reference_documents provided. Each applicant has_one application.

    There are three gems that I'm using to create the application. Paperclip is to upload and store files. Prawn is used to create a pdf file with all the information that was stored in the database. And CombinePDF is used to combine all the pdf files into a single one that will get stored in application.

    Applicant Model (partial)

    class Applicant < ActiveRecord::Base
    	has_one :application, dependent: :destroy
    
    	has_many :reference_documents, dependent: :destroy
    	
    	has_attached_file :cv, path: "#{Rails.root}/storage/:attachment/:id/:filename"
    	validates_presence_of :cv_file_name
    	validates_format_of :cv_file_name, with: /pdf\Z/i, message: "must be a PDF file"
    	do_not_validate_attachment_file_type :cv
    

    ReferenceDocument Model (partial)

    class ReferenceDocument < ActiveRecord::Base
      belongs_to :applicant
    
      has_attached_file :doc, path: "#{Rails.root}/storage/:attachment/:id/:filename"
    	validates_presence_of :doc_file_name
    	validates_format_of :doc_file_name, with: /pdf\Z/i, message: "must be a PDF file"
    	do_not_validate_attachment_file_type :doc
    

    Application Model

    class Application < ActiveRecord::Base
      belongs_to :applicant
    
      has_attached_file :info, path: "#{Rails.root}/storage/application/:attachment/:id/:filename"
      do_not_validate_attachment_file_type :info
       
    end
    

    Let's just look at the applicants_controller because that's where most things happen. (When references are uploaded, similar methods will be called to update the application.)

    The create method does most of the work. (Later, update will repeat most of this as well.)

     def create
        @applicant = Applicant.new(applicant_params)
        if @applicant.save
          @applicant.send_thanks_for_applying
          @applicant.send_request_for_recommendation
          generate_application(@applicant)
          redirect_to thanks_path
        else
          render :new
        end
      end
    

    Let's look at the generate_application method.

      def generate_application(applicant)
        @applicant = applicant
        info = make_pdf_of_info(@applicant)
        pdf = CombinePDF.new
        pdf << CombinePDF.load("#{info}")
        pdf << CombinePDF.load("#{Rails.root}/storage/cvs/#{@applicant.id}/#{@applicant.cv_file_name}")
        unless @applicant.reference_documents.empty?
          @applicant.reference_documents.each do |ref|
            pdf << CombinePDF.load("#{Rails.root}/storage/docs/#{ref.id}/#{ref.doc_file_name}")
          end
        end
        pdf.save "#{Rails.root}/tmp/#{@applicant.fullname_no_spaces}_travel.pdf"
        @application = Application.create!(info: File.open("#{Rails.root}/tmp/#{@applicant.fullname_no_spaces}_travel.pdf"), applicant_id: @applicant.id)
      end
    

    The first step is to make a pdf with whatever info is stored in the database. Looking at that method:

      def make_pdf_of_info(applicant)
        @applicant = applicant
        @file = "#{Rails.root}/tmp/#{@applicant.fullname_no_spaces}.pdf"
        Prawn::Document.generate("#{@file}") do |pdf|
          pdf.text "#{@applicant.fullname}"
          ... (more lines like above)
        end
        return "#{@file}"
      end
    

    Along with creating the file, it also returns the name of the file created. The generate_application method can then use this file name, along with the stored CV file and any references to make the final application. Once we have this file, the last line in the method, "uploads" it to the Application model along with the applicant's id.

    That's basically it. We now have a single file with all the information for an applicant. As references come in, we'll run the same methods, but will have to change the create! to an update! because each applicant only has one application.