Валидация моделей в рельсах, неявное связывание

Я пытаюсь проверить две модели в рельсах.

Увольнение имеет условие, которое гласит: "Если у вас есть тип увольнения, который называется" боулинг ", то у вас должен быть" 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. Это происходит внутри транзакции, поэтому вы не окажетесь в несогласованном состоянии, если один из двух не удастся сохранить.

Другие вопросы по тегам