我有以下代码和测试,我似乎无法通过。代码应该是自动锁定24小时前完成的所有预订。
当我把一个撬进测试并运行Booking.auto_lock_guests的第一行时,没有任何反应。当我键入booking_7并在类型Booking.auto_lock_guests之后,它会更改锁定为true。这是否与设置它没有出现在Booking.all中的方式有关?或者这是我写测试的方式?
非常感谢任何帮助。
def self.auto_lock_guests
bookings = Booking.where(guests_completed: true, locked: false)
bookings.each do |booking|
next unless booking.guests_completed_at <= 1.day.ago
booking.locked = true
booking.save
end
end
context 'auto_lock_guests' do
let(:booking_6) { FactoryGirl.create(:booking, date: Date.today - 5.day, guests_completed: true, guests_completed_at: DateTime.now, locked: false )}
let(:booking_7) { FactoryGirl.create(:booking, date: Date.today - 5.day, guests_completed: true, guests_completed_at: DateTime.now - 3.day, locked: false )}
before do
Booking.auto_lock_guests
end
it 'should only lock bookings with a guests_completed date older than a day ago' do
expect(booking_7.locked).to eq(true)
expect(booking_6.locked).to eq(false)
end
end
答案 0 :(得分:1)
let
被懒惰地评估了。当before
块被执行时,没有记录,因为尚未调用let
块。
将let
更改为let!
以立即执行阻止,或者在booking_6
之前调用booking_7
和Booking.auto_lock_guests
编辑:
你也不能检查booking.save
是否成功。如果booking.save
失败 - 你永远不会知道。 :)
next unless booking.guests_completed_at <= 1.day.ago
可能会被重写为查询:where(Booking.arel_table[:guests_completed_at].gt(1.day.ago))
答案 1 :(得分:1)
您不需要首先遍历记录。事实上,当你的应用程序缩放时它会引起问题,因为将所有这些记录拉入内存将耗尽服务器(或dynos)内存。
您可以从数据库中选择记录并在单个查询中更新它们:
class Booking
def self.auto_lock_guests!
bookings = Booking.where(guests_completed: true, locked: false)
.where('guests_completed_at <= ?', 1.day.ago)
bookings.update_all(locked: true)
end
end
许多单独的UPDATE查询与一次更新多行之间的执行时间差异可能很大。
要测试它,您可以创建多个记录并使用更改期望:
# use describe and not context for methods.
describe ".auto_lock_guests" do
# let! is not lazy loading
let!(:old_booking) { FactoryGirl.create(:booking, date: 7.days.ago, guests_completed: true, guests_completed_at: 3.days.ago, locked: false )}
let!(:new_booking) { FactoryGirl.create(:booking, date: Date.today, guests_completed: true, guests_completed_at: DateTime.now, locked: false )}
it 'locks a booking with a guests_completed date older than a day ago' do
expect do
Bookings.auto_lock_guests! && old_booking.reload
end.to change { old_booking.locked }.from(false).to(true)
end
it 'does not lock a when guests_completed date is less than a day ago' do
expect do
Bookings.auto_lock_guests! && new_booking.reload
end.to_not change { new_booking.locked }.from(false).to(true)
end
end
在测试更改数据库的方法时,使用change
是一个非常好的主意,因为它们会验证初始状态和结果。
答案 2 :(得分:0)
在调用Booking.auto_lock_guests之后,我最终不得不将其添加到之前的操作中。它有效。
before do
Booking.auto_lock_guests
booking_7.reload
booking_6.reload
end