FactoryGirl 在工厂中设置 updated_at 属性

FactoryGirl set updated_at attribute in factory

使用 FactoryGirl 4.7.0,我有一个工厂,我想将 updated_at 属性指定为过去的日期。

factory :living_arrangement do

    trait :expired do
        updated_at Date.new(2012, 3, 6)
        # or
        updated_at { Date.new(2012, 3, 6) }
    end
end

但是这些都不起作用。工厂 updated_at 属性不断设置回 Date.now

如何让它工作?

原来我必须在创建工厂时使用回调,就像这样

factory :living_arrangement do
    trait :expired do
        after :create do |living|
            living.updated_at = Date.new(2012, 3, 6)
        end
    end
end

ActiveRecord 的自动时间戳功能集 Time.now 用于 created_at and updated_at 字段覆盖 FactoryGiril 值。这是 ActiveRecord 的默认行为。幸运的是,它可以被禁用

LivingArrangement.record_timestamps = false

创建带有自定义时间戳的模型后,您可能会想要重新打开自动时间戳。但是在单元测试的许多地方关闭和打开它会非常麻烦。您可以创建 test_helper,像这样

 def without_timestamping_of(*klasses)
    if block_given?
      klasses.delete_if { |klass| !klass.record_timestamps }
      klasses.each { |klass| klass.record_timestamps = false }
      begin
        yield
      ensure
        klasses.each { |klass| klass.record_timestamps = true }
      end
    end
  end

你可以像这样在你的规范中使用这个助手

without_timestamping_of LivingArrangement do
  create(:living_arrangement, :created_at => 1.week.ago, :updated_at => 1.week.ago)
end

或多个工厂

without_timestamping_of LivingArrangement, User do
  create(:living_arrangement, :created_at => 1.week.ago, :updated_at => 1.week.ago)
  create(:user, :created_at => 1.week.ago, :updated_at => 1.week.ago)
end

另一种常见的方法是使用 TimeCop gem

您快完成了,但是您需要保存并跳过 validations/callbacks,这应该完成 after :create,如下所示:

trait :expired do
  after :create do |living_arrangement|
    living_arrangement.update_columns(updated_at: 2.months.ago)
  end
end