Tips from Rails Anti-Patterns

Another good Ruby book is out, Rails Anti-Patterns. The book is loaded with good tips on everything from following the Law of Demeter to cleaning up your views with the use of helper methods.

Here are some things I picked up from the book.

delegate can take a :prefix argument

The delegate method from active_support is used for delegating calls
to another object without having to write out the full delegating
methods. It can take a prefix option to customize the name of the
delegating methods.

class Address
	@attr_accessors :street, :zip
end

class Person
	attr_reader :address
	# prefix => true, results in the model name being used as prefix
	delegate :street, :zip, :to => :address, :prefix => true
	#@person.address_street, @person.address_zip
end

class Person
	attr_reader :billing_address, :delivery_address
	# prefix => string, uses the string as prefix
	delegate :street, :zip, :to => :address, :prefix => delivery
	#@person.delivery_street, @person.delivery_zip
	delegate :street, :zip, :to => :address, :prefix => billing
	#@person.billing_street, @person.billing_zip
end

Transaction Scope

The code executed in the ActiveRecord callbacks execute in the same
transaction as the actual call to save, create, update, or delete.
Knowing this helps to eliminate unneccessary explicit transactions.

# Using a before filter
class Drink
	before_create :remove_ingredients_from_bar

		def remove_ingredients
			ingredients.each do |ingredient|
				Bar.remove(ingredient)
			end
		end
	end

	# Is better than using an explicit transaction
	class Drink
		def create_drink
			transaction do
			remove_ingredients
			create
		end
	end

	def remove_ingredients
		ingredients.each do |ingredient|
			Bar.remove(ingredient)
		end
	end
end

Association Methods

It is possible to add methods directly on the activerecord associations.
This is especially handy if the method uses information from both sides
of the relation.

class Drink
	#has_field :minimum_drinking_age
end

class Customer
	#has_field :age

	has_many :drinks do
		def allowed
			# proxy_owner is the object defining the relation, Customer
			where(['minimum_drinking_age < ?', proxy_owner.age])
		end
	end
end

When to make a model active

If there is no user interface for adding, removing, or managing data,
there is no need for an active model. A denormalized column populated
by a hash or array of possible values is fine.

This is really just the application of the KISS principle, Keep It
Simple Stupid, but I have never seen it as clearly described before
reading this book.

Haml []

A nice feature of Haml that I didn’t know about, is the [] operator.
When given an object, such as [record], [] acts as a combination of
div_for and content_for, outputting a tag with the id and class
attributes set appropriately.

-# This Haml
%span[@team]


RESTful actions

When using resources in Rails there are seven methods that are used.

index, create, show, update, delete, edit, and new. The first five
naturally map to get(collection), post(collection), get(singular),
put(singular)
, and delete(singular), but what isn’t as obvious is
that.

The new and edit actions are really just different ways of representing
the show action.

This is of course obvious when you think about it, but once again Chad
and Tammer has written it down in plain simple English.

Rake Tasks

How should you treat your application specific Rake tasks on order to
test them easily. Once again the solution is very simple.

Write the domain specific code as a class method on the appropriate
model associated with the task.

Then all you have to do is call the method from the task.

task :fill_bar_with_ingredients do
	Bar.fill_with_ingredients
end

It is not always appropriate to add this functionality to the existing
models. This is a clue that another model is needed in your domain.

task :fill_bar_with_ingredients do
	LiquorStore.order_ingredients
end

Database Index

Since most applications have far more reads than writes, you should add
indexes to every field that appears in a WHERE clause or an ORDER
clause. You should also add indexes for every combination of fields that
are used that are combined with AND.

As always, don’t follow this advice blindly, if a table only has three
rows then perhaps the index is overkill…

Conclusion

Apart from these tips, there are tons of other useful information,
making this book a must-read if you are doing Rails development.

Leave a Reply

Close Menu