james james - 2 months ago 12
Ruby Question

Rspec test passing only when there's a PUTS in the model

The

puts
statement must be having some kind of weird effect that I'm not seeing here...

I have an
Order
model. There's a callback on the model where the callback requires the model to be fully committed; i.e., I need to use an
after_commit
. However, the determinant of if the callback should run or not requires
ActiveRecord::Dirty
and therefore requires a
before_save
(or
after_save
, but I use
before_save
based on some other non-essential info).

I have combined the two thusly:

class Order
# not stored in DB, used solely to help the before_save to after_commit transition
attr_accessor :calendar_alert_type, :twilio_alerter

before_save
if self.calendar_alert_type.nil?
if self.new_record?
self.calendar_alert_type = "create, both"
elsif self.email_changed?
self.calendar_alert_type = "update, both"
elsif self.delivery_start_changed? || self.delivery_end_changed? || (type_logistics_attributes_modified.include? "delivery")
self.calendar_alert_type = "update, start"
elsif self.pickup_start_changed? || self.pickup_end_changed? || (type_logistics_attributes_modified.include? "pickup")
self.calendar_alert_type = "update, end"
end
end

puts "whatever"
end

after_commit do
if self.calendar_alert_type.present?
calendar_alert(self.calendar_alert_type)
end
end
end

def calendar_alert(alert_info)
puts "whatever"
alert_type = alert_info.split(",")[0].strip
start_or_end = alert_info.split(",")[1].strip
if start_or_end == "both"
["start","end"].each do |which_end|
Calendar.send(alert_type, which_end, self.id)
end
else
Calendar.send(alert_type, start_or_end, self.id)
end
end


All of the private methods and the
ActiveRecord::Dirty
statements are working appropriately. This is an example of a spec:

it "email is updated" do
Calendar.should_receive(:send).with("update", "start", @order.id).ordered
Calendar.should_receive(:send).with("update", "end", @order.id).ordered
find("[name='email']").set("nes@example.com")
find(".submit-changes").click
sleep(1)
end

it "phone is updated" do
... #same format as above
end


Literally all the specs like the above pass ONLY when EITHER
puts
statements is present. I feel like I'm missing something very basic here, just can't put my finger on it. It's super weird because the
puts
statement is spitting out random text...

*Note, I'm totally aware that
should_receive
should be
expect_to_receive
and that I shouldn't use sleep and that expectation mocks on feature tests aren't good. Working on updating the specs separately from bad code days, but these shouldn't be causing this issue... (feel free to correct me)

Answer

This behavior depends on your Rails version. Before Rails 5 you can return anything except false value to keep on running. A false will abort the before_* callback chain. puts 'whatever' returns a nil. So every thing works. Your if block seems to return a false (custom implemation for calendar_alert_type?). In this case the chain is holded.

With Rails 5 you have to throw(:abort) to stop callback handling.

Comments