OUR BLOG

Thoughts on development, design and the world we live in.



remarkable validations for rails 3

By sarah in Uncategorized. Posted on July 21st

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:

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

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

[code]
rails new remarkable_app -T"
cd remarkable_app
[/code]

add to Gemfile:
[code]
group :development, :test do
gem "rspec", "2.6.0"
gem "rspec-rails", "2.6.1"
gem "remarkable_activerecord", "4.0.0.alpha4"
end
[/code]

Then back on the command line, set up rspec:
[code]
rails g rspec:install
[/code]

edit spec/spec_helper.rb to include (after require ‘rspec/rails’):
[code]
require 'remarkable/active_record'
[/code]

Create a Model

Then make a model to play with (on the command line):
[code]
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
[/code]

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

Test Driven Validation

Let’s test drive our first validation..
[code]
describe Person do
should_validate_length_of :name, :within => 3..40
end
[/code]

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.

[code]
$ 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
[/code]

add validation to my model…

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

Test passes!

[code]
$ 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
[/code]

More validations:
[code]
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
[/code]

Reasonably nice error output:
[code]
$ 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
[/code]

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:
[code]
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
[/code]

Watch it fail:
[code]
$ 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
[/code]

Make it pass:
[code]
$ 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
[/code]

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.

Update: remarkable 4.0 is still at alpha. Meanwhile, shoulda has been refactos to offer a set of rspec matchers

By sarah | Posted in Uncategorized | Comments (0)

Post a Comment

Your email is never shared. Required fields are marked *

*
*