remarkable validations for rails 3

I’ve been working on upgrading an app from Rails 2.3.11 to Rails 3.1.  It was using the old rspec-on-rails-matchers plugin to get validators like:

it 'verifies that login is between 3 and 40 characters' do
   User.new.should validate_length_of(:login, :within => 3..40)
end

I like that validation syntax, but lately when I see a plugins, I worry that I’m in for some archaeology. I did find a replacement gem, but it didn’t work on first try, so I read up on my options. I briefly considered shoulda, which is now compatible with rspec, but I settled on remarkable because it seems to match the syntax already in use. I wrote a little test rails app with a couple of models and was pleased the results.

Setup

rails new remarkable_app -T"
cd remarkable_app

add to Gemfile:

    group :development, :test do
      gem "rspec", "2.6.0"
      gem "rspec-rails", "2.6.1"
      gem "remarkable_activerecord", "4.0.0.alpha4"
    end

Then back on the command line, set up rspec:

rails g rspec:install

edit spec/spec_helper.rb to include (after require ‘rspec/rails’):

    require 'remarkable/active_record'

Create a Model

Then make a model to play with (on the command line):

rails g model person name:string email:string
rake db:migrate
rake spec
/Users/sarah/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -S bundle exec rspec ./spec/models/person_spec.rb
*
Pending:
  Person add some examples to (or delete) /Users/sarah/src/mv/experiment/remarkable_app/spec/models/person_spec.rb
    # Not Yet Implemented
    # ./spec/models/person_spec.rb:4
Finished in 0.00026 seconds
1 example, 0 failures, 1 pending

yay! ready to get started test driving some remarkable validations…

Test Driven Validation

Let’s test drive our first validation..

describe Person do
  should_validate_length_of :name, :within => 3..40
end

note that remarkable also supports:
it { should validate_length_of :name, :within => 3..40 }
For my new code I’ll probably write the more concise version, but it is nice that my old code should work.

$ rake spec
/Users/sarah/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -S bundle exec rspec ./spec/models/person_spec.rb
F
Failures:
  1) Person
     Failure/Error: send(should_or_should_not, send(method, *args, &block))
       Expected Person to be invalid when name length is less than 3 characters
     # ./spec/models/person_spec.rb:4:in `block in <top (required)>'
     # ./spec/models/person_spec.rb:3:in `<top (required)>'
Finished in 0.30367 seconds
1 example, 1 failure
Failed examples:
rspec /Users/sarah/.rvm/gems/ruby-1.9.2-p290@remarkable_rails3/gems/remarkable-4.0.0.alpha4/lib/remarkable/core/macros.rb:26 # Person
rake aborted!
ruby -S bundle exec rspec ./spec/models/person_spec.rb failed

add validation to my model…

class Person < ActiveRecord::Base
  validates_length_of :name, :within => 3..40
end

Test passes!

$ rake spec
/Users/sarah/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -S bundle exec rspec ./spec/models/person_spec.rb
.
Finished in 0.27601 seconds
1 example, 0 failures

More validations:

describe Person do
  should_validate_length_of :name, :within => 3..40
  should_allow_values_for :email, "[email protected]"
  should_not_allow_values_for :email, "sarah", "@foo", "whatever.com"
end

Reasonably nice error output:

$ rake spec
/Users/sarah/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -S bundle exec rspec ./spec/models/person_spec.rb
..F
Failures:
  1) Person
     Failure/Error: send(should_or_should_not, send(method, *args, &block))
       Did not expect Person to be valid when email is set to "sarah"
     # ./spec/models/person_spec.rb:6:in `block in <top (required)>'
     # ./spec/models/person_spec.rb:3:in `<top (required)>'
Finished in 0.29054 seconds
3 examples, 1 failure
Failed examples:
rspec /Users/sarah/.rvm/gems/ruby-1.9.2-p290@remarkable_rails3/gems/remarkable-4.0.0.alpha4/lib/remarkable/core/macros.rb:26 # Person
rake aborted!
ruby -S bundle exec rspec ./spec/models/person_spec.rb failed

Cheated a little on implementation by copying email validation from ActiveRecord docs… all good.

Now let’s add an association!

In app/model/person.rb:

describe Person do
  should_validate_length_of :name, :within => 3..40
  should_allow_values_for :email, "[email protected]"
  should_not_allow_values_for :email, "sarah", "@foo", "whatever.com"
  should_have_many :addresses
end

Watch it fail:

$ rake spec
/Users/sarah/.rvm/rubies/ruby-1.9.2-p290/bin/ruby -S bundle exec rspec ./spec/models/person_spec.rb
...F
Failures:
  1) Person
     Failure/Error: send(should_or_should_not, send(method, *args, &block))
       Expected Person records have many addresses, but the association does not exist
     # ./spec/models/person_spec.rb:7:in `block in <top (required)>'
     # ./spec/models/person_spec.rb:3:in `<top (required)>'
Finished in 0.32615 seconds
4 examples, 1 failure

Make it pass:

$ rails g model address street:string person:belongs_to
      invoke  active_record
      create    db/migrate/20110721161741_create_addresses.rb
      create    app/models/address.rb
      invoke    rspec
      create      spec/models/address_spec.rb
$ rake db:migrate
.
Pending:
  Address add some examples to (or delete) /Users/sarah/src/mv/experiment/remarkable_app/spec/models/address_spec.rb
    # Not Yet Implemented
    # ./spec/models/address_spec.rb:4
Finished in 0.2998 seconds
5 examples, 0 failures, 1 pending

the rest is left as an exercise for the reader :)

Summary

Overall, I like the remarkable syntax. It seems reliable and on its way to a good release for Rails 3.

Post a Comment

Your email is never shared. Required fields are marked *

*
*