Валидация моделей в рельсах, неявное связывание
Я пытаюсь проверить две модели в рельсах.
Увольнение имеет условие, которое гласит: "Если у вас есть тип увольнения, который называется" боулинг ", то у вас должен быть" BowlingRecord ".
class Dismissal < ActiveRecord::Base
include DismissalHelper
belongs_to :bowling_record
validate :dismissal_bowling_record_combo_is_appropriate
def dismissal_bowling_record_combo_is_appropriate
return if !dismissal_type.present?
if bowling_record.present?
return if DismissalHelper::BOWLING_DISMISSAL_TYPES.include?(dismissal_type)
errors.add(:dismissal_type, "#{dismissal_type} can't have a bowler!")
else
return if !DismissalHelper::BOWLING_DISMISSAL_TYPES.include?(dismissal_type)
errors.add(:dismissal_type, "#{dismissal_type} must have a bowler!")
end
end
end
У BowlingRecord есть условие, которое гласит: "Если у вас есть какие-то увольнения, то они должны быть определенного типа увольнения" (одним из которых является Bowled).
class BowlingRecord < ActiveRecord::Base
include DismissalHelper
has_many :dismissals
validate :dismissals_go_against_bowler
def dismissals_go_against_bowler
dismissals.each do |dismissal|
if !DismissalHelper::BOWLING_DISMISSAL_TYPES.include?(dismissal.dismissal_type)
errors.add(:dismissal, "can't be #{dismissal.dismissal_type} if registered against a bowler")
end
end
end
end
У меня проблемы с построением этого, реально я хочу сделать что-то вроде:
BowlingRecord.create!(
extra_balls: 5,
maidens: 3,
runs: 56,
dismissals: [ Dismissal.create!(dismissal_type: :bowled) ]
)
Но это взрывается, потому что, когда мы создаем увольнение, оно совершенно справедливо говорит: "Мне нужна запись в боулинг, если вы хотите, чтобы ваш тип был в боулинге". Но вся информация здесь, я хочу, чтобы создание Увольнения было ленивым, чтобы оно имело контекст, который он создает, принадлежащий записи боулинга.
Конечно, я говорю создать запись боулинга заранее, а затем добавить увольнения один за другим. Но это, кажется, более грязный код, и поэтому мне было интересно, есть ли способ сделать это таким образом...
Спасибо
1 ответ
Вы могли бы .build
соответствующее увольнение:
record = BowlingRecord.new(
extra_balls: 5,
maidens: 3,
runs: 56
)
record.dismissals.build dismissal_type: :bowled
record.save!
.build
:
Возвращает новый объект типа коллекции, который был создан с атрибутами и связан с этим объектом, но еще не был сохранен.
См. http://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html для получения дополнительной информации.
Через http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html увольнение сохраняется автоматически при сохранении родительского BowlingRecord. Это происходит внутри транзакции, поэтому вы не окажетесь в несогласованном состоянии, если один из двух не удастся сохранить.