Consider the following code:
campaign_spec.rb:
describe Campaign do
before :each do
@campaign = Campaign.new
end
it { should validate_presence_of :position }
end
campaign.rb:
class Campaign < ActiveRecord::Base
attr_accessible :position
validates :position, presence: true
default_scope order(:position)
before_validation :next_position
# sets the position to the next id (1 if none exist) before validation
def next_position
if self.position.blank?
self.position = Campaign.select("coalesce(max(position),0) + 1 as position").reorder(nil).first.position
end
end
end
spec output:
Failures:
1) Campaign should require position to be set
Failure/Error: it { should validate_presence_of :position }
Expected errors to include "can't be blank" when position is set to nil, got errors: ["name can't be blank (nil)"]
# ./spec/models/campaign_spec.rb:9:in `block (2 levels) in <top (required)>'
From what my model is saying, I should be able to create a Campaign
without giving it a position. It sets the position if none exists before validation. So why is my spec not passing? I'm thinking that maybe it's not calling my before_validation
method?
should validate_presence_of
sets the value of the attribute to nil and then runs the validations. Since it is nil, nil.blank?
returns true
, so your callback is executed, setting it back to some value, and hence validation is found not to work.
Fact is that you don't need to validate this field if you are sure it is never empty. Instead, write the test to check whether it is indeed automatically populated when set to nil.
it 'populates position if blank before validations' do
subject.position = nil
subject.valid?
subject.position.should_not be_nil
end