Onward!

I got a late start yesterday, but got a few tasks that needed to be done taken care of. First, I went to Menards and found that they had the piece to finish the vent in the kitchen. So I went from this:

photo-1

to this:

photo-4

without too much trouble. So my ductwork in the kitchen is done.

Next, I thought I should really fix the one valve in the basement that's leaking. It took a while, but in the crummy picture below you can see where I cut the old valve out and put a new one it. And as far as I can tell, there are no leaks.

photo-2

Lastly, I forgot to run the water line to the refrigerator. So I needed to do that. This required me to buy one more piece of copper pipe, since I didn't have enough. I also didn't do such a great job with these pipes, so they look a little crooked. But I'll have to live with it. And you can see from the shot below that I had already installed the insulation when I was sweating the valve to the pipe. So I melted a bit of it. I did have a piece of metal in front of it so that it didn't catch on fire. But it got pretty hot and melted some. You'll notice how it looks wet, which was me frantically spraying water on stuff to make sure nothing caught on fire.

photo-3

Lastly (though it actually was the first thing I did yesterday), I picked up my new window. It's pretty heavy, but I got it in the house. Installing that will be a job for my drywalling party.

photo-5

All I have left to do before the drywalling party now is to install the vent for the hood, finish putting the insulation up and run the last piece of pvc pipe to the second floor. I should be able to get those things done next weekend or during the week. So I'm going to schedule it. It should take place in March! Yay!

Quebec and Montréal Trip

Went to Quebec City and Montréal with my sister Julie and Mom. Pictures are here:

Quebec and Montreál

The flight out had a stopover in Toronto before getting us to Montréal. We then rented a car and drove to Quebec. It took us about six hours to go the under 200 miles because there was a lot of snow. Quebec Carnivale was going on at the time, so there were a lot of people there. We just walked around the city, which is very old and very cool. Since it was snowy and slippery, we had to take it easy with Mom. But she was a trooper and saw a lot of the city.

The next day we drove back to Montréal and the snow was cleared, so we got there in about two hours. Montréal was about 10 degrees colder than Quebec and had a brutal wind. Since we also wore Mom out quite a bit in Quebec, we didn't make her do much walking in Montréal. We did eat lunch at our hotel, while waiting for the room to be ready and got to watch the Canadian hockey team play an Olympic game. All the waiters were watching as was pretty much anyone who came to the restaurant. Fortunately, Canada won in overtime.

After a short walk to the underground mall in Montréal, Mom got her gifts for all the grandkids and was happy to go back to the hotel to give her legs a rest. Julie and I then braved the cold to check out Montréal. We saw a lot. I heard there's a bike ride here in June and I'd like to come back sometime to do it.

Big snowstorm in Chicago when we were heading back, so we spent the day at the airport. Finally took off around 7 and after a somewhat bumpy ride home, we got in around 9. Definitely crazy to go to Canada in winter, but it was fun.

Rails Constantize Method

I learned a new inflector method the other day, constantize. Here's the method I used it in.

def allowed_to_read?(role)
  level = "Document::CAN_READ_" + self.readinglevel.upcase
  arr = level.constantize
  return true if "#{arr}".include? "#{role}"
end

I have an app where only certain people are allowed to read certain documents. So each user is assigned a role and then each document is assigned a group saying who is allowed to read it. I named the roles and readinglevels the same and then made a constant in the model that's named, for example:

CAN_READ_ASSISTANT = ["assistant", "associate"]

So when I'm checking if someone is allowed_to_read a document, I look at the document's readinglevel and join it to the string "Document::CAN_READ_". Then what I want to do is find out if the user's role is included in the array named the same as the string I just created. That's exactly what the constantize method does. If I didn't have the line arr = level.constantize and I just tried to do an include? on the level variable above, I'd get an error that include? is not a method for a string. But after the constantize method is run, it finds the array just fine.

Paperclip and Nested Attributes

I have an app that has a model (called cases) that has_many documents associated with it. I have had no problems in creating the case and the associated documents. I had quite a bit of trouble when I was trying to replace one of the documents with and updated one. But I finally got that straightened out. Not sure if this is how a real programmer would do it, but it works for me.

cases_controller.rb

  def index
    if permitted_to? :create
      @case = Case.new
      Document::DOC_CLASSES.each_with_index do |d, i|
      @case.documents.build(doc_class: Document::DOC_CLASSES[i])
    end
  end

  def edit
    @case = Case.find(params[:id])
  end

  def create
    @case = Case.new(case_params)
    if @case.save
      pid = fork do
        @case.generate_merged_document
      end
      redirect_to cases_path
    else
      redirect_to cases_path
    end
  end

  def update
    @case = Case.find(params[:id])
    if @case.update(case_params)
      pid = fork do
        @case.generate_merged_document
      end
    redirect_to cases_path
    else
      render action: 'edit'
    end
  end

A couple of things to note here. I'm making a new case from the index path. That's just because it's easier for this app. There's more to the index method, but that's the relevant part for this post. The Document::DOC_CLASSES.each goes through the list of documents that I'm allowed to have for each case. The only other different thing is my generate_merged_document method. Which does merge all the uploaded pdf files into one, because that's something I needed to do.

case.rb

  has_many :documents, dependent: :destroy
  accepts_nested_attributes_for :documents, allow_destroy: true

This is all I have in the model having to do with the document.

document.rb

  belongs_to :case 
  has_attached_file :doc, path: "#{Rails.root}/storage/:attachment/:id/:filename"

This is all that's in the document model having to do with the case.

To me, all the magic happened in the view. I have a partial that I use for the form.
_form.html.erb

<%= form_for(@case) do |f| %>
  Firstname: <%= f.text_field :firstname %>
Lastname: <%= f.text_field :lastname %>

<%= f.fields_for :documents do |g| %> <% if params[:action] == 'edit' %> <%= g.hidden_field :id %> <%= g.hidden_field :doc_class %> <% if g.object.doc_file_name %> <%= g.file_field :doc %> <%= g.object.doc_class %> (Current: <%= g.object.doc_file_name %>) <% else %> <%= g.file_field :doc %> <%= g.object.doc_class %> (Not uploaded) <% end %> <% else %> <%= g.file_field :doc %> <%= g.collection_select :doc_class, Document::DOC_CLASSES, :to_s, :titleize %> <% end %>
<% end %>

<%= f.submit 'Submit' %> <% end %>

So this is just making a regular form. But the fields for the nested document are different, depending on whether it's and edit action or not. If it is an edit action, it's putting the current id and doc_class in hidden fields (because those won't change) and showing a file_field to enable the uploading of a new document. And just so I knew what I had, it's showing the current document if one has already been uploaded. For a new case, it just shows a file_field for each possible document that could be uploaded.

Took me a while to get here, but I think this works pretty well. I know I'll come across this again in the future, so I'm just documenting it for myself so I remember how to do it.

Hate Things that Depend on Whitespace

I'm writing a rails app and was trying to use a scope with a variable. My code looked like this:

scope :ternal, -> (kind) { where kind: kind }

This worked fine on my laptop, but when I uploaded it to my production server, the app wouldn't start and I got a message something like this:

syntax error, unexpected tLPAREN_ARG, expecting keyword_do_LAMBDA or tLAMBEG scope :ternal, -> (kind) { where kind: kind }

Do you see the problem? It's the space after the arrow. To fix things, I just needed to take it out. So this works fine:

scope :ternal, ->(kind) { where kind: kind }

I'm not much of a programmer, but whitespace-dependent stuff drives me nuts. I think this is actually why I dislike using python. I didn't think ruby ever had anything like this, but I guess they do.

Thanks to this site for pointing it out to me.