Well, it’s been nearly a year, but I’m finally riding the Rails again.  I’ve dusted off my old app that I was working on a year ago and in the past few days I’ve added some features to it.  The main thing I’ve been working on is support for uploading multiple images to a single model, with the ability to dynamically indicate how many you want.  As an added bonus, it also has the ability to crop the images.

After reading what seems like a thousand blogs, reviewing this plugin after that plugin, I found a great post by Mike Fischer.  I tried his sample application, and with a few tweaks, it seems like it will suite my need quite well.  The only problem is, my old app is on Rails 1.2.6 and it has some plugins that are old (and apparently not updated for Rails 2), but Mike’s technique requires Rails 2.

One of the plugins my Rails app uses is paginating_find, and it seems that is no longer maintained at all, as I cannot even access the site anymore.  Since Rails 1.2.6 is old anyway, I’d like to upgrade my app, and will probably use will_paginate instead of paginating_find, though I chose the former due to its performance benefits, and I haven’t yet read about the performance of will_paginate.  If anyone is familiar with that aspect of it, please let me know.

It’s obviously been a while since I’ve posted, so I wanted to provide an updated. I’ve been inured with too many things that have distracted me from my Rails project for a time, though I hope to return to it soon as I hope it will be profitable for me in more ways than one. I’ve lately been playing with Grails, the need arising at work for a quick and simple blog-like tool to provide status updates via RSS to an existing Java web application.

This exercise has been interesting and helped me see the great similarities between Grails and Rails, as well as some differences. Truthfully I haven’t spent much time with Grails, so I don’t have much to report yet, except that Groovy is and since it compiles to Java bytecode that makes it a lot easier to use at existing Java shops than Rails. On the other hand, for side projects that will live on the Internet on commodity hardware, be it shared or private, Rails is a great framework.

One thing I will make note of in the hope that it will be useful to someone else, is that if you are working with Grails and wanting to deploy a WAR to some servlet container that only implements Servlet Specification 2.3 you can do the following:

grails -Dservlet.version=2.3 war

This requires, I think, at least version 1.0.1 of Grails. I did it with version 1.0.1 and 1.0.3. Of equal or more importance, though, is to set the app.servlet.version property in the application.properties file to 2.3, since that is the value that will actually be used when generating the web.xml for your application (where it really matters).

Unfortunately I ran into other problems (NoSuchMethodError on org.apache.tools.ant.ProjectHelper.getImportStack()) which I have yet to get around. I was deploying to WebLogic 8.1.6 and, so far as I know, the only version of ant in the classpath is the version deployed with the WAR, which is 1.7.0.

I hope to play around with Grails more, preferably on a real project that might start small and grow into something valuable to someone. And I somehow have to find time to get back to my Rails side project.

Rails by default uses a system-generated primary key called “id” for all persisted objects. I personally like this (for the very reasons Dave Thomas outlines in the Rails book on pp. 286-287), but if you don’t, you can change it. Like Dave, I don’t recommend it, but here’s how if you must.

class Friend < ActiveRecord::Base
self.primary_key = "email"
end

Now the primary key of the Friend class is “email” and you must set this value before you can save the object. This is one caveat of being able to change the primary_key from the convention (but don’t complain, at least you can do it).

I chose this example to point out why I like using system-generated, non-model-related primary keys. Email address seems at first like a reasonable field to use for the primary key because they must be unique between people* and they don’t change (often). But they do change (for example if someone use’s their ISP for email and they change their ISP). If you use it as the primary key and your best friend moves from Boston to Idaho and gets a new email address, you have to update all of the places that it’s used as a foreign key (and in the case of your best friend, this may be quite a few places).

Stick to the default system-generated ID and you’ll be better off. But at least you can change the default if you must.

Composite Keys

Rails doesn’t support composite keys natively, but there are plugins available that accommodate this, such as Nic Williams CompositeKeys.
* In the case of a married couple who shares the same email address, you would not be able to include both the man and the woman (who might both be your friends) in your contact list.

Have you ever wish you could tell Rails the name of the table that mapped to your model class?  Perhaps you want a model to represent a legacy table (which could be any table that already exists which is either too painful to recreate or over which you have no control).  Or perhaps you just want to be strange and call your class “This” and your table “that” (not something I’d recommend, but if you must satisfy that urge, you can).  Here’s how:

class Customer < ActiveRecord::Base
set_table_name "customp"
end

Now Rails will look for the table called “customp” when persisting or reading instances of Customer.  You can also use the more direct form:

class Customer < ActiveRecord::Base
self.table_name = "customp"
end

This tip comes from page 282 of the Rails book.

I have found as I’ve been working on my project that Rails has many very useful little features that may not be used all that often but are sometimes needed. As I come across them I hope to note them here in the hopes that they will help someone (myself included) at some point.

Yesterday I was reading the Agile Web Development with Rails (2nd Edition) book (hereafter AWDwR2E) and came across these useful little pieces of knowledge.

Leveraging ActiveRecord in a non-Rails application

Start by including rubygems and then include the activerecord gem:

require “rubygems”
require_gem “activerecord”

Next, establish your database connection:

ActiveRecord::Base.establish_connection(:adapter => “mysql”, :host => “localhost”, :database => “yourdatabase”)

Then, create a class that extends ActiveRecord::Base so your class will take advantage of all of the ORM plumbing that ActiveRecord provides:

class Friend < ActiveRecord::Base
end

Note that you should have a table called friends in yourdatabase for this to work. Assuming your friends table has the columns name and email, you could locate a friend named “John Doe” and update his email address with the following lines:

john_doe = Friend.find(“John Doe”)
john_doe.email = “john.doe@gmail.com”
john_doe.save

That’s all there is to it, and that’s pretty awesome!  This (ActiveRecord) is one of the really great features of Rails that makes it so easy to write a database-driven application.  Unlike most ORM frameworks, ActiveRecord (and by extension, Rails) relies on convention rather than configuration and thus you don’t have to tell it what table represents your class or what columns in the table map to what properties in your class.  It uses reflection to determine all of this although you can override it’s defaults if you need to do so.

I got tired of seeing the deprecation warnings about the old Rails pagination helpers, so I decided to seek out a better approach, but of course I wasn’t going to implement it myself.  With all of the skilled Rails pros out there, I had every intent of leveraging someone’s else’s success.

I succeeded, thanks to Ilya Grigorik and Alex Wolfe.  Ilya wrote “Faster Pagination in Rails” which leverages Alex’ paginating_find plugin to provide limited result sets at the database level.  Ilya’s post includes code he wrote to provide a neat and tidy presentation of the pagination links.

It only took me a few hours to get it working.  It should not have taken this long, but I’m notorious for making things harder than they need to be.  In this case, after I grabbed the code from Ilya’s post and installed the paginating_find plugin for my application, I modified my view to use Ilya’s helper.  This is where it all went wrong.  I was about to do something like this

<%= render :partial => ‘shared/pagination’ %>

but instead did this

<%= windowed_pagination_links(@results) %>

As it turns out neither one of these is correct, but the second one is even more incorrect than the first and led me down a bad path for a couple hours (just what every developer hates).  Since I don’t ever want to repeat that mistake again, and perhaps someone else out there is having this same trouble, I’m writing about it.

What I saw in my functional tests after modifying my view as above (and the associated controller) was

ActionView::TemplateError: undefined method `page’ for #
On line #22 of app/views/sell/list.rhtml

This frustrated me for hours because I couldn’t figure out why it didn’t recognize the page method.  I checked the code, double-checked Ilya’s blog (and many comments) and checked my code to confirm that I was specifying the :page option to the find method.  Sure enough.  Here’s what my controller had

@stuff = Listing.find_by_all_user(session[:user_id],
:page => {:size => 10, :current => params[:page]})

Now if you know about paginating_find, you may notice a problem with the code above.  But since paginating_find was brand new to me, I didn’t notice it.  I’ll explain the problem here shortly.  First let me explain the problem with my view.

What I really needed to have is

<%= render(:partial => ‘shared/paginate’, :locals => {:collection => @stuff}) -%>

So it turns out that I started out on the right path, but left off a critical piece, which is the passing of the controller-returned collection @stuff to the partial so it can do it’s rendering.  If I had even once executed the code using this render(:partial) approach, I’d have been at least on the right path.

Once I got this figured out, I still had problems.  My controller test was still failing with an error like this

ActionView::TemplateError: undefined method `page_count’ for #
On line #2 of app/views/shared/_paginate.rhtml

I returned to Ilya’s blog and read more comments, re-reviewed the entry itself and didn’t see what I was doing wrong.  Then I looked more closely and noticed that all of the references to the use of the paginating_find plugin were using the find() method of any given model.  So I thought perhaps it’s called paginating_find for a reason, that being that it works only with the find() method, not with the Rails dynamic methods find_by_XXX and find_all_by_XXX.  But I was using find_all_by_user (where user is the property of my model that I wanted to find stuff by.

So a quick update to my code fixed the problem and all tests are passing.

@stuff = Stuff.find(:all, :conditions => ['user=?', session[:user_id]],
:page => {:size => results_per_page, :current => params[:page], :first => 1})

Now I’m a happy camper on the Rails.

I need to be able to assert that a response from a Rails controller doesn’t contain certain content, for example when the same action will respond to both GET and POST methods.  In my case I’m writing a register method in a LoginController and I want it to render the same view, but if the registration was successful I do not want the registration form to be displayed again and instead want some text that answers the question, “Ok, I’ve registered, what next?”

Turns out this is easy (I should have known).  I found the answer on this Cheat Sheet.  The assert_select test helper accepts an equality? parameter, so give it false and it ensures that the content does not contain the value specified in the selector parameter.

I recently resumed work on a Rails project I started a few months ago only to find that some of the functional tests that Rails generated for some scaffolding code were failing. These tests were failing on a fresh checkout from Subversion, so it was obvious that I’d neglected to run the functional tests before at least my last checking a few months prior. That of course was a problem, but now I’ve corrected that by figuring out a better way to ensure that I can always run the tests.

I spent all day yesterday working on functionality other than the one controller that was failing. I saw the failing tests but decided that since they were on controller code that was generated by scaffolding, I would let them go. I actually thought perhaps the tests were generated wrong, but of course that was not the case. Since I’m now using autotest, I decided I’d better figure out why those tests were failing because I just couldn’t bare to see those failures flashing before me all day while I’m working (and I didn’t want my little project to suffer from the Broken Window theory).

I started by looking at the failures, of which there were four (the real controller name has been changed to protect the innocent).

1) Failure:
test_create(SomeControllerTest)
[/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/assertions/response_assertions.rb:26:in `assert_response'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/assertions/response_assertions.rb:18:in `assert_response'
test/functional/some_controller_test.rb:59:in `test_create']:
response to be a <:redirect>, but was <200>

2) Failure:
test_edit(SomeControllerTest) [test/functional/some_controller_test.rb:72]:
is not true.

3) Failure:
test_show(SomeControllerTest) [test/functional/some_controller_test.rb:40]:
is not true.

4) Failure:
test_update(SomeControllerTest)
[/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/assertions/response_assertions.rb:26:in `assert_response'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.6/lib/action_controller/assertions/response_assertions.rb:18:in `assert_response'
test/functional/some_controller_test.rb:77:in `test_update']:
response to be a <:redirect>, but was <200>

4 tests, 10 assertions, 4 failures, 0 errors

So I started by looking at the test for Failure 1 to see if there was anything odd going on. I noticed that the test was trying to create the model without any of its properties. So I went to the code and sure enough, if a save was successful it was redirecting and if not it would render the new action. Since no properties of the model were being passed to the controller, no model was being created. A quick modification to the test to pass in the required properties and it was passing.

At first I hard-coded these properties into the test, but then I took at look at the fixtures and decided I should be using those. It was a good thing I did, too, because it turns out the remainder of the tests were failing due to bad fixture data. The first two fixture entries were missing some properties that, after the original creation of the model, were added as required properties. So I added the missing properties and, to my pleasant surprise, the rest of the failing tests passed.

So the moral is: keep your fixtures updated as you modify your model, especially if adding required properties. AND, more importantly, always run your tests and you’ll know right away as soon as you break something (at which time it will be much easier to figure out what caused it).

I recently ran into a problem with Ruby on Rails on my Mac when trying to execute the following command in a new Rails project.

rake db:migrate

The error I received was as follows.

dyld: NSLinkModule() error
dyld: Library not loaded: /usr/local/mysql/lib/mysql/libmysqlclient.15.dylib
Referenced from: /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib/mysql.bundle
Reason: image not found
Trace/BPT trap

A quick Google search turned up a blog post by Peter Morris that had just the answer I needed. The relevant portion for this problem is excerpted below.

This is because the latest version of MySql has changed a path from lib/mysql to just lib/. To fix this problem you need to type the following (it’s all one line):

sudo install_name_tool -change /usr/local/mysql/lib/mysql/libmysqlclient.15.dylib /usr/local/mysql/lib/libmysqlclient.15.dylib /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib/mysql.bundle

Thanks, Peter!