Headlines

Redline Labs

Here in the Redline Labs you will find an assortment of solutions to problems that we encountered while working on projects of our own.

Ruby on Rails Plugins

Our RoR plugins can be found at http://www.agilewebdevelopment.com/plugins/owner/72

Ruby on Rails - adding :include support to the with_scope method

Our patch for this new functionality can be viewed at http://dev.rubyonrails.org/ticket/4132.

This patch has now been accepted and will be in Rails 1.1.

The need for adding :include comes from the fact that :joins are a bit too straight forward (you get what you ask for). If you are joining multiple tables, each with their own id field for example, then the id for the actual object(s) you are trying to find could be clobbered by the id field of a joined table. This could lead to some difficult bugs to track down.

Enter :include. With :include we can get similar functionality to joins but now our fields for our models are seperated for each join table and we no longer see our data getting clobbered by data in other tables.

Before:

Developer.with_scope(:find => {:joins => 'left outer join projects on developers.project_id = projects.id'}}) do
  Developer.find(:all, :conditions => 'developers.id = 1 and projects.id = 2')
end

With the :joins there, you'd expect to get the developer with an id of 1, but the way the records in the returning hash are assigned, you'll actually get a developer with its id assigned to be 2; the id of the project... not good!.

Try this...

irb(main):001:0> {:id => 1, :id => 2}
=> {:id=>2}

This is essentially why you don't get the id you'd expect.

After:

Developer.with_scope(:find => {:include => :projects}}) do
  Developer.find(:all, :conditions => 'developers.id = 1 and projects.id = 2')
end

Now with the :include, we will get just what we expect... a developer with an id of 1. Check your logs of the generated sql between the two approaches. With :include, each field is decorated with a table prefix to keep everything nice and seperate.

Ruby on Rails - fixing the error_messages_for method

A patch has been submitted at http://dev.rubyonrails.org/ticket/4186. So if and when that gets accepted you can instead just use the code below for now.

This patch has now been accepted and will be in Rails 1.2.

One minor difference from the code seen below is that :default has been renamed to :object_name

The error_messages_for method which is contained in any scaffold generated form code is a nice handy method for showing any errors associated validation failures for an object.

eg.
error_messages_for 'user'

Now if a form on a page works with more than one model and you want to show the error messages for both, then you have to provide two calls to the method passing the name of the object to each.

eg.
error_messages_for 'user_common'
error_messages_for 'user'

Not only does this not look very nice by producing two distinct error blocks, but also shows the seperation of the data in the form when these details should probably be hidden from the user.

Our solution involves improving the error_messages_for method to allow errors in this case to be combined into one grouping such as this...

eg.
error_messages_for 'user_common', 'user', :default => 'user'

What this does is allow the one method to show errors for both user_common and user and the :default option tells the method which object to say its producing the errors for in the title. If the :default option is left off, it uses the first object name in the parameter list, in this case user_common. The errors are listed in the order the oject names are listed. So since we want to show user_common errors first and user errors second, and we don't want the error section saying that 'X errors prohibited this user common from being saved', we set the :default to user so that we instead get 'X errors prohibited this user from being saved'.