What? You’re still generating migrations manually? I don’t anymore. I have tools which do it for me.

Hobofields is a set of extensions to ActiveRecord that gives us lots of goodies, including the ability to generate migrations automatically. The key to achieving this automatic property declaration is schema declaration in the model.

1 class Post < ActiveRecord::Base
2   fields do
3     title :string
4     published_at :datetime
5     timestamps
6   end
7 end

If you ever used DataMapper, the idea is similar. Where Hobofields shines though is in reading your model and inferring many, many conventions:

1 class Comment < ActiveRecord::Base
2   belongs_to :post
3 end

Running the hobo_migration generator results in:

 1 $ script/generate hobo_migration
 2 
 3 ---------- Up Migration ----------
 4 add_column :comments, :post_id, :integer
 5 
 6 add_index :comments, [:post_id]
 7 ----------------------------------
 8 
 9 ---------- Down Migration --------
10 remove_column :comments, :post_id
11 
12 remove_index :comments, :name => :index_comments_on_post_id rescue ActiveRecord::StatementInvalid
13 ----------------------------------

If you use acts_as_list, Hobofields also knows to add a position column (or whatever name is needed):

1 class Comment < ActiveRecord::Base
2   acts_as_list
3 end

Running the migration generator, you get:

 1 $ script/generate  hobo_migration
 2 
 3 ---------- Up Migration ----------
 4 add_column :comments, :position, :integer
 5 ----------------------------------
 6 
 7 ---------- Down Migration --------
 8 remove_column :comments, :position
 9 ----------------------------------
10 What now: [g]enerate migration, generate and [m]igrate now or [c]ancel? 

Another thing I love about Hobofields is rich type support. Need Textile?

1 class Post < ActiveRecord::Base
2   fields do
3     body :textile
4   end
5 end

 1 content = <<EOTEXTILE
 2 This is some Textile content
 3 
 4 h1. Automatically formatted
 5 
 6 To your:
 7 
 8 * specifications,
 9 * using standard tools
10 EOTEXTILE
11 
12 Post.new(:body => content).body.to_html
13 #=> "<p>This is some Textile content</p>\n<h1>Automatically formatted</h1>\n<p>To your:</p>\n<ul><li>specifications,</li>\n<li>using standard tools</li>\n</ul>\n"

Or maybe you need an enumeration?

1 class Comment < ActiveRecord::Base
2   fields do
3     status enum_string(:spam, :ham), :default => :spam, :required => true
4   end
5 end

 1 $ script/generate hobo_migration
 2 
 3 ---------- Up Migration ----------
 4 add_column :comments, :status, :string, :default => "ham", :required => true
 5 ----------------------------------
 6 
 7 ---------- Down Migration --------
 8 remove_column :comments, :status
 9 ----------------------------------

1 >>Comment.new.status
2 #=> "ham"
3 >> Comment.create!(:status => "foo")
4 #=> ActiveRecord::RecordInvalid: Validation failed: Status must be one of spam, ham

Admittedly, this last example could be better handled with Hobo’s lifecycle (state machine) implementation, but still, it’s nice that the validation already exists. Using :null => false, :required => true creates the appropriate validation as well:

1 class Comment < ActiveRecord::Base
2   fields do
3     author :string, :required
4     email  :string, :required
5     status enum_string(:spam, :ham), :required => true, :default => "ham"
6     timestamps
7   end
8 end

And Hobofields is smart enough to know when no changes are required:

1 $ script/generate hobo_migration
2 Database and models match -- nothing to change

But with this model definition, we now have new validation automatically:

1 >> Comment.create!
2 #=> ActiveRecord::RecordInvalid: Validation failed: Author can't be blank, Email can't be blank

Oh wait, just realized that the email address should be an email address:

1 class Comment < ActiveRecord::Base
2   fields do
3     email :email_address, :required
4   end
5 end

1 >> Comment.create!(:email => "a")
2 #=> ActiveRecord::RecordInvalid: Validation failed: Author can't be blank, Email is invalid

I really enjoy Hobofields for all the goodies it brings to the table. I haven’t even started on all the automatic scopes goodies, the lifecycle methods (which I haven’t used yet), or scoped associations.

Until we meet again tomorrow, I suggest you read Hobofields Reference, as well as Hobofields rich types to get the full goods.

Search

Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend

Links

Projects I work on

Projects I worked on