There are a plethora of fixture plugins that attempt to make your test fixtures less of a pain in the arse to work with. And most do succeed in one manner or another.
Well one of the nicest fixture plugins, called Rathole, has just been sucked down into rails – and it’s a doozy. Let’s summarize so you can decide whether to dive in or not.
Let’s use the following model for this example:
1 2 |
class Company < ActiveRecord::Base; has_many :employees; end class Employee < ActiveRecord::Base; belongs_to :company end |
Just a simple one-to-many association between a company and its employees, easy enough. But when we get into setting up our fixtures there’s a lot of non-essential stuff and easy to mess up ids we have to manually specify. And all this just gets exponentially hairier as the data-set increases.
companies.yml
1 2 3 4 5 |
yfactorial: id: 1 name: yFactorial, LLC created_at: <%= Time.now %> updated_at: <%= Time.now %> |
employees.yml
1 2 3 4 5 6 |
ryan: id: 1 name: Ryan Daigle company_id: 1 created_at: <%= Time.now %> updated_at: <%= Time.now %> |
With Rathole’s features you no longer need to manually reconcile the cross referenced ids and to set the auto-magic date column values. Watch carefully what your fixtures can be when they grow up:
companies.yml
1 2 |
yfactorial:
name: yFactorial, LLC |
employees.yml
1 2 3 |
ryan: name: Ryan Daigle company: yfactorial |
- You no longer have to specify the id for each record. That’s automatically done for you as the hash of the name of the record (so the integer hash of
"yfactorial"becomes that record’s id) - No need to specify the auto-magic date field values anymore. All the
created_xxandupdated_xxfields will be automatically populated withTime.now - When referencing other record ids (as in
employees.company_id), you can just put the fixture name and it will resolve that column to be the pk value of the referenced record. This is what allowed me to change thecompany_id: 1line inemployees.ymlto becompany: yfactorial.
Note: Since the primary keys of each record are calculated (as a hash of the fixture name), the fixture doesn’t need to be loaded before knowing what it’s pk value will be. This resolves a lot of the recursive dependency and ordering issues you might’ve otherwise encountered with an approach such as this.
But there’s more… Foreign key references get especially twisted when you have join tables that govern your has_and_belongs_to_many associations. So assume a company has_and_belongs_to_many industry_associations:
1 2 3 4 5 6 7 8 |
class Company < ActiveRecord::Base has_and_belongs_to_many :industry_associations, :join_table => 'company_industry_associations' end class IndustryAssociation < ActiveRecord::Base has_and_belongs_to_many :companies, :join_table => 'company_industry_associations' end |
Instead of having to write our own company_industry_associations.yml fixture file, we can just reference the collection of associations a company belongs to inline in companies.yml:
companies.yml
1 2 3 |
yfactorial:
name: yFactorial, LLC
industry_associations: ruby, webservices |
Assuming there’s an industry_associations.yml fixture file that specifies records named ruby and webservices, the habtm join table will be automatically populated for you.
This is a really big win for you fixture users (of which I am one). Perhaps those that have turned their nose up at fixtures will take a second look? Really great functionality – thanks, John, for the contribution!
Take a look at the bottom of the plugin’s README file to see how to setup default values and how to fetch the pks of other fixtures
tags: ruby, rubyonrails
