Question

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?

Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top