Rails validation spec fails (but code works in development env)


#1

I’m not sure if this is the best way to validate a foreign key in rails,
but I am using the following validation to do so (Rails 3, Rspec 2):

class Item < ActiveRecord::Base
validates :manufacturer_id, :inclusion => { :in =>
Manufacturer.all.collect { |m| m.id } }
end

While I can create a new valid Item record in the console with the code
above, it doesn’t work in my spec. The contents of my spec:

describe Item do
it “is valid when a manufacturer with manufacturer_id is in the
database” do
@manufacturer = Manufacturer.create!
@item = Item.new(:manufacturer_id => @manufacturer.id)
puts “VALIDATION ERRORS: #{@item.errors}”
puts “ID WE’RE CHECKING FOR IN THE DB: #{@item.manufacturer.id}”
puts “IDs THAT ARE IN THE DB: #{Manufacturer.all.collect { |m| m.id
}.to_s}”
@item.should be_valid
end

Which fails with:

Item
VALIDATION ERRORS: {:manufacturer_id=>[“is not included in the list”]}
ID WE’RE CHECKING FOR IN THE DB: 2
IDs THAT ARE IN THE DB: [1, 2]
is valid when a manufacturer with manufacturer_id is in the database
(FAILED - 1)

Failures:

  1. Item valid when manufacturer_id is in database
    Failure/Error: @item.should be_valid
    expected valid? to return true, got false

    ./spec/models/item_spec.rb:47:in `block (2 levels) in <top

(required)>’

As you can see in the information I printed with the spec output, the ID
of the manufacturer is clearly in the array which the validation is
using to check inclusion. Any reason why this wouldn’t work in the test
env, but it would in development?

Thanks for your help!
Dave


#2

Hi there,

di you ever find the answer? I am having the same issue now, really
weird.


#3

I came across the same issue. I was trying to accomplish exactly the
same thing like the original poster (make sure that association is with
an actual record in the DB). I came across the same issue too, and after
a little debugging the core the solution is to use Proc.

This has to do with loading mechanics, IMO: when you run the spec, first
the model definition is loaded, there are no records in the DB yet, so
:in option is just empty array (I debugged this to be true). But if you
use Proc in that place, then the query to get records from DB is
executed “lazily”; by that time your spec has correct context setup
(manufacturers table populated) and thus you get correct behavior from
spec.

In your case you should use:

validates :manufacturer_id, :inclusion => {
:in => Proc.new { Manufacturer.all.collect { |m| m.id } }
}