Reputation: 3659
I have simple model:
class Category < ActiveRecord::Base
belongs_to :board
validates :name, presence: true, uniqueness: {scope: :board_id}
validates :board, presence: true
validates :display_order, presence: true, uniqueness: {scope: :board_id}
before_save :set_display_order
private
def set_display_order
last = self.board.categories.order("display_order DESC").last
self.display_order = last.display_order + 100 if last
end
end
When I added this before_save callback, these tests start to fail:
it { should validate_uniqueness_of(:display_order).scoped_to(:board_id) }
it { should validate_uniqueness_of(:name).scoped_to(:board_id) }
With error (this if for the line in private method last = ...
):
NoMethodError:
undefined method `categories' for nil:NilClass
Other shoulda tests work fine:
it { should validate_presence_of(:name) }
it { should validate_presence_of(:board) }
it { should belong_to :board }
Any idea what is problem here? I tried to change before_save
to before_validation
but still the same.
Upvotes: 3
Views: 1890
Reputation: 4566
One way around this limitation of shoulda_matchers and AR callbacks is to redefine the subject of the test which shoulda matchers uses.
example:
# category_spec.rb
# assuming you're using factorygirl and have this setup correctly
let(:board) { FactoryGirl.create(:board, :with_many_categories) }
subject { FactoryGirl.build(:category, board: board) }
# your shoulda matcher validations here
Upvotes: 1
Reputation: 5998
Because shoulda creates record in DB. Gem creates record skipping validations
http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/Shoulda/Matchers/ActiveModel#validate_uniqueness_of-instance_method
Ensures that the model is invalid if the given attribute is not unique. It uses the first existing record or creates a new one if no record exists in the database. It simply uses ':validate => false' to get around validations, so it will probably fail if there are 'NOT NULL' constraints. In that case, you must create a record before calling 'validate_uniqueness_of'.
In your case created category
is empty it means category.board # => nil
and you call method categories
from nil.
You should create a record yourself for tests on uniqueness.
Upvotes: 2