big*_*ato 6 rspec ruby-on-rails
我一直以为.save并.save!会更新updated_at现有记录的列.这不是真的吗?如果是这样,那么每次保存时我是否需要创建一个before_save过滤器来更新它?
今天是6月18日:
Loading development environment (Rails 4.1.1)
irb(main):001:0> o = Order.last
Order Load (0.4ms) SELECT `orders`.* FROM `orders` ORDER BY `orders`.`id` DESC LIMIT 1
=> #<Order id: 24, user_id: 1, order_date: nil, total_cents: 0, total_currency: "USD", shipping_cents: 0, shipping_currency: "USD", tax_cents: 0, tax_currency: "USD", subtotal_cents: 0, subtotal_currency: "USD", created_at: "2014-06-13 21:24:38", updated_at: "2014-06-13 21:24:38", status: "Incomplete", coupon_id: nil>
irb(main):002:0> o.save!
(0.4ms) BEGIN
(0.3ms) COMMIT
=> true
irb(main):003:0> o.updated_at
=> Fri, 13 Jun 2014 21:24:38 UTC +00:00
irb(main):004:0> o.reload
Order Load (0.7ms) SELECT `orders`.* FROM `orders` WHERE `orders`.`id` = 24 LIMIT 1
=> #<Order id: 24, user_id: 1, order_date: nil, total_cents: 0, total_currency: "USD", shipping_cents: 0, shipping_currency: "USD", tax_cents: 0, tax_currency: "USD", subtotal_cents: 0, subtotal_currency: "USD", created_at: "2014-06-13 21:24:38", updated_at: "2014-06-13 21:24:38", status: "Incomplete", coupon_id: nil>
irb(main):005:0> o.updated_at
=> Fri, 13 Jun 2014 21:24:38 UTC +00:00
Run Code Online (Sandbox Code Playgroud)
我关心这个的原因是因为我正在包装一个函数的内部,ActiveRecord::Base.transaction所以我想测试它们在出现问题时不会更新:
Rspec测试(当它不应该时,它会一直传递,因为无论成功或失败,updated_at都不会被更改):
it "rollsback the transaction" do
...
order.stub(:save!).and_raise(StandardError)
expect { payment_info.save }.not_to change { [billing_address.updated_at,
shipping_address.updated_at,
order.user.updated_at,
order.updated_at] }
end
Run Code Online (Sandbox Code Playgroud)
我的方法:
def process_billing_info!
ActiveRecord::Base.transaction do
billing_address.save!
shipping_address.save!
user.save!
order.update_all_fees!
end
rescue Exception => e
false
end
Run Code Online (Sandbox Code Playgroud)
MrY*_*iji 16
正如您在日志中看到的那样,没有UPDATE执行的SQL查询.Rails根本没有更新你的记录.这是因为.save实际上只有在对该记录进行了更改时才会保存记录.
.touch您可以调用方法来更新updated_at字段,而无需对记录进行更改:
1.9.3p489 :005 > Intervention.first.touch
Intervention Load (12.9ms) SELECT "interventions".* FROM "interventions" LIMIT 1
SQL (20.5ms) UPDATE "interventions" SET "updated_at" = '2014-06-18 16:34:03.924648' WHERE "interventions"."id" = 1
=> true
Run Code Online (Sandbox Code Playgroud)
这里我们看到UPDATESQL查询.
与@MrYoshiji 的回答一起,这是另一种使用方法.touch:
if o.save!
o.touch unless o.changed?
end
Run Code Online (Sandbox Code Playgroud)