shoulda-callback-matchers
shoulda-callback-matchers copied to clipboard
Callbacks with Proc condition not working
hello and thank you for your work, I have the following test case that doesn't seem to work:
test class
class Template::Box < ActiveRecord::Base
before_validation :set_initial_position, if: ->(box){ box.position.blank? }, on: :create
private
def set_initial_position
self.position = (self.brothers.maximum("position") || -1) + 1
end
end
test spec
is_expected.to callback(:set_initial_position).before(:validation).on(:create).if( subject.position.blank? )
for now It seems to work locally with a quick fix to the file "active_model.rb":
def matches_conditions? subject, callback
if rails_version >= '4.1'
# !@condition || callback.instance_variable_get(:"@#{@condition_type}").include?(@condition)
!@condition || callback.instance_variable_get(:"@#{@condition_type}").map{|cond| cond.is_a?(Proc) ? cond.call(subject) : (cond == @condition) }.include?(true)
else
!@condition || callback.options[@condition_type].include?(@condition)
end
end
and also by changing this line in the "matches?" method:
matches_conditions?(callback) &&
to matches_conditions?(subject, callback) &&
Interesting - the reason this works is that you set the @condition
to true, which might be a misunderstanding.
I'd suggest to set this up to either stub the position in a context like so:
context "with no position set" do
before do
subject.stub(:position, nil)
end
it { is_expected.to callback(:set_initial_position).before(:validation).on(:create) }
end
Or, if you want to use the if
chain, devise a private method for position presence like so:
Implementation:
class Template::Box < ActiveRecord::Base
before_validation :set_initial_position, unless: :has_position?, on: :create
private
def has_position?
!!self.position
end
def set_initial_position
self.position = (self.brothers.maximum("position") || -1) + 1
end
end
Test:
is_expected.to callback(:set_initial_position).before(:validation).on(:create).unless(:has_position?)
Let me know if this is working for you
Guess I'll change the proc condition with a private method for now, thanks for your time and your suggestions.
Should this be closed?