Thursday, April 9, 2015

Easy peasy AJAX requests, couched in a Rails / Coffeescript environment

What follows is a pretty standard POST using ajax, but I've had to do this sporadically enough that I felt the need to write it down for my own posterity. Since I'm most comfortable in Rails, the setting for this exercise will still be a Rails app.

Let's say you have a UsersController and POST route to /users. In order to POST to that route within a CoffeeScript (for example, users.js.coffeefile:

  $.ajax(
    url: '/users'
    type: 'POST'
    data: { name: 'Bob Roberts', age: '52' }
  ).done (data) ->
    // do something with data returned
    return

Inside your UsersController#create method, the params hash will have the data you submitted, so:

  params[:name]
  # => 'Bob Roberts'
  params[:age]
  # => '52'

Then, in your create method, you can do this:

def create
  @user = User.create(name: params[:name], age: params[:age])
  render json: @user
end

Fairly standard. The only thing slightly different is the render call, which will convert the object to a JSON hash and return it to the ajax POST as a data packet. That data object gets returned in the .done section of the ajax call for you to do with whatever you want.

This approach has come in handy for me on a surprising number of occasions, despite how little JS code I write on a daily basis, so it's very good to know.

Tuesday, April 7, 2015

Simple JavaScript tricks for address bar parsing

Ever wanted to get the current URL using JavaScript?

  window.location.href

You can also retrieve various pieces of it by replacing .href with .host, .protocol, or .pathname

(Thanks to CSS-tricks.com for the tips!)

Monday, April 6, 2015

Don't delete your migration files!

This is probably Rails 101 but this is something that I just had the extreme displeasure to experience, so I felt the need to comment. 

Exercise EXTREME caution when deleting a migration that has been deployed. 

This can seriously mess up your database.

I recently took over a project where the previous developer had two differently-named migration files trying to add the same column to the same table in the database, and it was messing things up. However, the first (incorrectly-named) file had already been migrated, leaving DuplicateColumn errors when trying to migrate the database when it got to the next migration. Since the first file was the one that was incorrectly named, I deleted that one. Unfortunately, that one had already been deployed to staging, so when I tried to migrate on the staging server, it still gave me a DuplicateColumn error because it saw the duplicate migration as a new migration that needed to run, and the first column was still in the schema.

Long story short (is that still possible?), I had to re-create the incorrectly-named migration file and remove the second migration file that was doing the same thing instead. Then, since I'm a teensy bit OCD and I don't like have migration files with incorrect names, I wrote a new migration to remove the column, migrated to update the schema, then deleted both migration files and created one last one that would add that needed column back into the database schema.

Needless to say, it was a huge hassle, and the moral of the story is: Be Very Careful Deleting Deployed Migrations.

Sunday, April 5, 2015

Speed up your app's delegation skills using `:includes`

My last post talked about delegating methods to a parent model using the delegate module. I want to talk about performance issues you could experience doing this, and a simple way to fix them and speed them up.

When querying databases, there's something called "eager loading" that essentially is a way for the code to pull associated objects that may be needed at the same time as pulling the main object, thereby saving a separate DB call and hopefully saving some time. I won't pretend to know exactly how this works, I just know that it's supposed to be faster to do it this way.

In my previous example, I had a Course with an associated CourseName, because I wanted to be able to create multiple Courses with the same name but different times and dates. I delegated the :name method to CourseName, so that instead of calling course.course_name.name, I can simply call course.name to achieve the same results. However, when I do that, it has to load the CourseName object on the fly, and that could result in some additional sluggishness. (Apparently, this is hotly debated whether these N+1 queries are faster or slower.)

This is where eager loading is helpful.

When you are finding a course with Course.find(params[:course_id]), throw in one additional thing to make this eager load the associated course name:

  Course.includes(:course_name).find(params[:course_id])

This helps remove the N+1 query and will hopefully help my performance. Now let's say I have a School object which has_many :courses. When I call school.courses, if I'm going to be displaying the course name as well, I'm into N+1 query land again. The easiest way to fix this is by adding it directly into the association in the School model:

class School < ActiveRecord::Base
  has_many :courses, -> { includes(:course_name) }
end

Whambo.


Hat Tip: http://blog.arkency.com/2013/12/rails4-preloading/ for the help in understanding preloading

Friday, April 3, 2015

A true leader (in Rails) knows how to delegate

When building a larger Rails app with lots of associations, I've run into an issue a few times where one object belongs to another, and I want to get the value of the parent object from the child object. This is going to get very esoteric very quickly, so let's get an example going.

Say I have a Course model with an associated CourseName (belongs_to :course_name), because I want to be able to create multiple Courses with the same name but different times and dates. Since Course does not have a name, any time I find a Course object and want to show the name, I have to call course.course_name.name. Previously, I've written a shortcut method on Course:

  def name
    course_name.name
  end

That isn't a huge issue, but if there are a lot of CourseName methods or attributes that I want to access directly from Course, it starts to be a pain having to define a new shortcut method for each.

This is where Rails' delegate module comes in very handy. Here's what the above example would look like using delegate:

class Course < ActiveRecord::Base
  belongs_to :course_name
  delegate :name, to: :course_name
end

I've delegated the name method that I would have had to define in Course to the CourseName model instead, so when I am working with a course object and I call course.name, it will look for the delegated method in the model that it was delegated to, based on the association.

This delegation stuff is pretty powerful and extendable according to the docs, so I'm looking forward to playing around a bit with all the other stuff that can be done.