Как использовать метод касания Ruby для предварительного заполнения начальных данных

Я использую метод Tap Ruby в моем seed.rb следующим образом:

 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 должны быть обновлены, поэтому я использую find_or_create_by Он работал нормально, но после того, как я добавил null: ложное ограничение в моем 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 , так как это создаст другой объект, если кто-то обновит инструмент: false до инструмента: правда


person Umesh Malhotra    schedule 18.04.2019    source источник
comment
Я считаю, что ошибка возникает, когда вы запускаете rails db:migrate, правильно? Если это так, то это просто потому, что у вас уже есть некоторые записи PaymentMode, поэтому создание столбца без указания значения по умолчанию будет означать присвоение ему значения nil, которое, очевидно, является тем, что вы указали в своей миграции, чтобы его не было.   -  person PericlesTheo    schedule 18.04.2019
comment
Ошибка возникает, когда я запускаю rake db:seed, пожалуйста, прочитайте вопрос еще раз   -  person Umesh Malhotra    schedule 18.04.2019
comment
О, я понимаю, что вы имеете в виду. Я не думаю, что это возможно с #find_or_create_by. Вероятно, проще всего было бы разбить его на несколько методов.   -  person PericlesTheo    schedule 18.04.2019
comment
Возможно, вы можете использовать create_with PaymentMode.create_with(instrument: false).find_or_create_by(name: "Cash")   -  person Smek    schedule 18.04.2019


Ответы (1)


Проблема не в методе tap. find_or_create звонок, буквально, violates not-null constraint. В tap вы работаете с существующим объектом, который не может быть записан в базу данных с аргументами, указанными в find_or_create_by. Есть также последовательные вызовы create и update вместо только create.

Есть еще один способ сделать это, который работает так же, как нажатие, но в блоке вы работаете с объектом до того, как он будет записан в базу данных:

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

Что касается меня... Я бы просто использовал вместо них find_or_initialize_by и save.

person Nick Roz    schedule 18.04.2019
comment
Да, это больше не давало мне PG::NotNullViolation: ERROR, но когда у меня есть проверка в моем приложении rails, например validates :name, :instrument, :bank_account_allocation, presence: true , я получаю эту ошибку: - ActiveRecord::RecordInvalid: Validation failed: Instrument can't be blank, Bank account allocation can't be blank - person Umesh Malhotra; 23.04.2019
comment
Ну, это потому, что false.blank? это true. Попробуйте другую проверку как validates :instrument, inclusion: { in: [true, false] } или exclusion: { in: [nil]} - person Nick Roz; 23.04.2019
comment
Ознакомьтесь с Руководством по проверке Active Record. Все эти вопросы там подробно рассматриваются - person Nick Roz; 23.04.2019