Showing posts tagged ruby on rails

Wrong way, Right way - Part 3 - Avoid unnecessary load in conditionals

Note: I’ve been using this technique for a while that I’d forgotten I was doing it. Thumbs up to CollectiveIdea for their post which reminded me and inspired the following.

Part of a series about common Ruby mistakes that make things slower or are just plain wrong. Not the style of the code (indentation, methods names etc), but the actual code itself. All examples use Ruby 1.9.2 and Rails 3.0.x.

Part 3 - Avoid unnecessary load in conditionals

The Wrong Way

if post.comments.any? && post.author.present? && post.public?
  puts post.comments.inspect
end

Whats wrong? The conditionals are executed in order. Suppose the post isn’t even public. Before we even get to that check at the end, we’ve hit the database twice; once to check for comments, and another to check for an author. 2 database queries that didn’t need to be run. This may not seem like much, but when you’ve got many of them in your app, you may be causing yourself unnecessary page load times.

The Right Way

if post.public? && post.author_id? && post.comments.any?
  puts post.comments.inspect
end

Whats better? We check if the post is public right away. If it isn’t, we’ve saved ourselves unneeded queries. On top of that, since we don’t use the author inside the block, we don’t need to load them. All the check wanted to know is if they have an author id. Rails provides a nice boolean style method for every field on an ActiveRecord model. So lets use them, in that case, utilizing ‘author_id?’ to check for an author without any additional queries. Then, finally, the comments are loaded, only when the other two, less time consuming checks have passed.

Questions? Comments? Let me know what you thought.

Wrong way, Right way - Part 2 - Work with eager loading, not against it

Part of a series about common Ruby mistakes that make things slower or are just plain wrong. Not the style of the code (indentation, methods names etc), but the actual code itself. All examples use Ruby 1.9.2 and Rails 3.0.x.

Part 2 - Work with eager loading, not against it

The Wrong Way

class Post < ActiveRecord::Base
  def last_comment
    comments.order(:position).last
  end
end

Post.includes(:comments).each do |post|
  puts post.last_comment
end

Whats wrong? The last_positioned_comment instance method on Post is adding an order to comment query, which negates the includes(:comments) part of the Post select query. As a result, you’ll get one query for all posts, one query for all comments, and one query for each post to get the last comment. (pattern: 1P + 1C + 1*P)

The Right Way

class Post < ActiveRecord::Base
  def last_comment
    comments.sort_by(&:position).last
  end
end

Post.includes(:comments).each do |post|
  puts post.last_comment
end

Whats better? Because no extra sort is added to the comments, the ones that were preloaded still match. So you end up with only two queries, one for all posts, and one for all comments. (pattern: 1P + 1C). To end up getting the proper sorting, you simply use Ruby’s sort_by method along with symbol to proc syntax to create a nice clean implementation that works with eager loading.

Questions? Comments? Let me know what you thought.

Wrong way, Right way - Part 1 - Optimized conditional data sections

Part of a series about common Ruby mistakes that make things slower or are just plain wrong. Not the style of the code (indentation, methods names etc), but the actual code itself. All examples use Ruby 1.9.2 and Rails 3.0.x.

Part 1 - Optimized conditional data sections

The Wrong Way

@comments = Comment.order(:position)
if @comments.count > 0
  @comments.each do |comment|
    …  
  end
end

Whats wrong? The conditional fires one query for count, and then the loop fires another one to get them again and instantiate them.

The Right Way

@comments = Comment.order(:position)
if @comments.to_a.any?
  @comments.each do |comment|
    …
  end
end

Whats better? Only one query is made. The conditional loads the records, so if there are any to loop over, they are already loaded and ready to go without an extra query.

Questions? Comments? Let me know what you thought.

Migrating from Github to Gemcutter

( cross-posted from http://blog.katipo.co.nz )

For those of you who follow this sort of thing, Github shut down their gem building. Thankfully, a newer and easier gem hoster, Gemcutter, appeared on the scene not long before that happened. The idea behind it, for those who haven’t heard of it, is that you manage your own gem building. Gemcutter doesn’t wait for your Gem spec to change before it makes a new gem. You simply build it locally, and push it to Gemcutter, using a handy gem they provide that extends Rubygems ‘gem’ console command.

But Github was building gems for some time, and due to it’s continuing popularity, many well known Ruby on Rails developers and companies switched permanently to Github for their gem building/hosting at the time, so it’s likely that quite a few gems you’ve got installed are from Github.

To help transition over from Github to Gemcutter, Maxim Chernyak wrote a great utility called off_github, which looks at your list of gems, and tells you which ones you’re installed from Github, and whether they can be reinstalled from Gemcutter. It saves a lot of time and effort  than having to do it manually. So here’s how to get started….

Read More