如何使用Ruby tap方法预填种子数据

How to use Ruby tap method to pre-fill seed data

我在 seed.rb 中使用 Ruby 的点击方法,如下所示:-

 PaymentMode.find_or_create_by(name: "Cash").tap do |pm|
  pm.instrument = false
  pm.bank_account_allocation = false
  pm.save!
 end

在 schema.rb 中,PaymentMode 模型如下所示:-

  create_table "payment_modes", force: :cascade do |t|
    t.string "name"
    t.boolean "instrument", null: false
    t.boolean "bank_account_allocation"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["name"], name: "index_payment_modes_on_name", unique: true
  end

我希望如果有人更新种子文件(例如有人可以更新 pm.bank_account_allocation = true)然后 运行 rake db:seed,相应的 payment_mode's数据应该更新,这就是我使用 find_or_create_by 的原因 它工作正常但是在我添加 null: false 约束在我的 PaymentMode 中(参见架构)后,我收到此错误:-

PG::NotNullViolation: ERROR:  null value in column "instrument" violates not-null constraint

我可以解决这个错误吗?如果没有,有没有办法将数据放入我的 seed.rb,以便如果有人更新种子,它应该更新相应的 ActiveRecord 对象?

P.S。我不想像这样 find_or_create_by 将受约束的列保留在参数中 PaymentMode.find_or_create_by(name: "Cash", instrument: false).tap ,因为如果有人将 instrument: false 更新为 instrument: true

,它将创建另一个对象

问题不在于 tap 方法。 find_or_create 字面意思是 violates not-null constraint。在 tap 中,您正在使用现有对象,无法使用您在中指定的参数将其写入数据库 find_or_create_by。还有 createupdate 的后续调用,而不仅仅是 create.

还有另一种方法,它的工作方式与 tap 类似,但在将对象写入数据库之前,您需要在块中对其进行操作:

PaymentMode.where(name: "Cash").first_or_create do |pm|
  pm.instrument = false
  pm.bank_account_allocation = false
end

至于我...我只是用 find_or_initialize_bysave 代替。