Future on Rails

Using Rails

Archive for the ‘Uncategorized’ Category

Nested Forms & Webrat

leave a comment »

I love the new features of Rails 2.3 – one beeing the support for nested forms (forms which let you edit multiple models and associations). However, I ran into some problems with this new approach: 1) Making complex forms with AJAX work with the Rails 2.3 approach and 2) Testing those forms with Cucumber and Webrat.

1) Making complex forms with AJAX work with the Rails 2.3 approach

When I tried to use the approach from Ryan Bate’s railscast “Complex Forms Part 3”, ran into several issues with organizing my partials and getting the HTML and Javascript right. Fortunately, Ryan addressed this issue himself => see his github project.

2) Testing those forms with Cucumber and Webrat

Another problem I ran into was testing a complex AJAX form with the new nested forms. Imagine the default app for managing projects, where each project has multiple tasks. To add tasks to a project, I can simply click “Add Task” on the project’s edit page and add form fields dynamically via AJAX. However, how would you address those fields in a cucumber step using webrat?

Given I am on the project edit page
When I click “Add Task”
And I fill in ??? with “my new task”
And I click “Save”
Then I should see …

What to insert for the “???” ? Those fields all have the same label (“Task:”) and the name/id is very cryptic, containing a randomly generated id. I couldn’t find an elegant solution for this issue yet. Please tell me if you know of any solution!

Advertisements

Written by Matthias Orgler

September 30, 2009 at 1:21 pm

Posted in Uncategorized

Tagged with , , , , , ,

The Widespread Abuse of Fixtures

leave a comment »

I thought, everyone on this planet already knew about the purpose of fixtures in Rails…unfortunately I see  the abuse of fixtures in many projects out there.

Fixtures are used by developers for many purposes: unit testing, integration testing or populating the DB with default data. But from all these usage scenarios, fixtures are really only good for integration testing! Don’t use fixtures for unit testing! Don’t use fixtures for populating the DB with default data!

Why not to use fixtures for unit testing?

Fixtures for unit testing is a bad idea. The main reason is that your unit tests become hard to read, because you need two code artefacts to understand them. You also introduce a dependency between test and fixtures (and between this test and other tests using the same fixture data!). It is recommended by most developers, to build unit test objects directly in the test class. This makes every test precondition explicit in the code. It is also easy, because you usually only need an object of one class (without associations).

Why not use fixtures for populating the DB?

It is also very common, to use fixtures for loading default or sample data into the database. But since fixtures are also used for (automated) testing, you might want to separate those two concerns. My recommendation is to use fixtures exclusively for automated integration testing and to use a rake task to populate the DB with default data or test data for manual testing. By using gems like Populator and Faker, you can also quickly create sensible, randomized test data, so that your human testers can do their job. See the great Railscast on “Populating a Database”.

Written by Matthias Orgler

May 11, 2009 at 1:03 pm

Posted in Uncategorized

Named Scope or Virtual Attribute?

leave a comment »

The nice thing with Ruby is that it adheres to a basic OO principle: attributes and methods of a class should not be distinguishable. This way the client of class doesn’t have to know, whether “User.full_name” is an attribute or a method. In Rails this could also be a database column, an association or a named scope (all methods dynamically created by Rails). It is very convenient, that all those magic methods and attributes look and act the same :). However, I recently stumbled across a pitfall with named scopes and virtual attributes:

In my application, every “User” can have several “Bands”, of which he is the owner. Furthermore he can belong to several “Bands” as a member:

class User
  has_many :band_members,     :foreign_key => 'member_id'
  has_many :bands_as_member,  :through => :band_members, :source => 'band'
  has_many :bands_as_owner,   :class_name => 'Band', :foreign_key => 'owner_id'
  has_many :bands_as_member, :through => :band_members
end
class Band
  has_many    :band_members
  has_many    :members, :through => :band_members
  belongs_to  :owner, :class_name => 'User'
end

I used the rather long association names in the User model on purpose. If I would have called one of them simply “band”, I could really only receive part of the user’s bands through this one association. What I need to get ALL bands of a user (i.e. those which he owns and of which he is a member), I will either have to define a named scope or a vritual attribute combining all bands. Initially I thought it wouldn’t make a difference, since both approaches result in something called “User.bands” which returns all bands of the user.

Imagine, we would have modelled this as a virtual attribute (as I did, because I found it easier to think up than a SQL query 😉 ):

class User

  def bands

    self.bands_as_owner + self.bands_as_member

  end

end

This thing returns an array of all bands. What’s wrong with this approach? Well, this virtual attribute doesn’t act exactly like a named scope or an association. If you try the followin in a typical Band controller, you get an error:

def destroy
  @band = current_user.bands.find(params[:id])
  @band.destroy
end

The error you get doesn’t really give a hint to what happens here. After reading some documentation about the internals of Rails, I came across the problem. The thing is: our virtual attribute returns a simple Ruby Array – which doesn’t come with the find method of Rails. In contrast, when Rails dynamically creates such a method for an association or a named scope, the returned object is a proxy only ACTING AS IF it was an Array. In addition it also enhances the object by Rails’ magical methods you know.

This difference between virtual attributes and named scopes in the case mentioned above can really bite you. So be aware of the subtle differences between both approaches.

Written by Matthias Orgler

April 30, 2009 at 2:19 pm

Posted in Uncategorized