Подтвердить что ты не робот

Как проверить вложенный объект модели в зависимости от состояния родительского объекта?

Я пишу магическую форму в рельсах; например несколько входных страниц для одного объекта модели.

Основы моего подхода - это те, которые описаны в Multistep form Ryan Bates railscast: http://railscasts.com/episodes/217-multistep-forms (в случае, если кто-то хочет знать ПОЧЕМУ за некоторым кодом ниже).

Объектами, находящимися под пристальным вниманием, являются "Участник", который имеет один "Адрес"

Моя проблема в том, что я хочу только проверить вложенный объект (адрес), когда пользователь пытается пройти через экран ввода адреса. В настоящее время это отслеживается с помощью атрибута в модели участника под названием "current_step"

Итак, у меня есть Участник:

class Participant < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
  validates_presence_of :first_name, :last_name, :if => self.current_step == "name"
  ...
  def steps = %w[ name address confirm ] # the steps the wizard will follow
end

И адрес:

class Address < ActiveRecord::Base
  belongs_to :participant
  validates_presence_of :address1, :state, :suburb, :postcode #, :if => participant.current_step == "address"
end

Принцип этого подхода заключается в том, что действие "create" вызывается на контроллере (не показан) для каждого шага мастера и проверяет только подмножество модели при каждом шаге.

В настоящее время, когда я заполняю первый экран ( "имя" ) и пытаюсь перейти на шаг адреса, проверка адреса запускается, и я возвращаюсь на экран "имя" с ошибками проверки для данных пустого адреса.

Итак, я попробовал несколько подходов здесь, заключительной частью которого было закомментированное условие проверки адресов, показанное выше, - это я нашел, не работает, поскольку я только создаю объекты-участники, но не спасая их. Поэтому @participant.address возвращает мне адресный объект, но @participant.address.participant имеет значение null, так как у адреса еще нет внешнего ключа участника_id для поиска его родительского.

Причиной моей борьбы является включение супер-удобного метода accepts_nested_attributes_for. Я ожидал использовать validates_associated для проверки, но я вижу, что тег accepts_nested_attributes_for отлично рисует параметры формы для создания вложенных объектов модели, но также гарантирует, что метод participant#valid? обращается к проверке адреса в ВСЕ ситуации.

Итак, моя дилемма заключается в том, как наилучшим образом использовать метод participant#valid? для действительной частичной полной модели, основанной на параметре current_step участника?

EDIT - обновлено, чтобы удалить дополнительную информацию и перейти к основной проблеме

4b9b3361

Ответ 1

Добавьте свой виртуальный атрибут в модель Address:

class Address < ActiveRecord::Base
  belongs_to :participant
  attr_accessor :skip_validation
  validates_presence_of :address1, :state, :suburb, :postcode, 
                           :unless => :skip_validation 
end

Задайте виртуальный атрибут в адресном объекте, когда установлен current_step.

class Participant < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
  attr_accessor :current_step
  validates_presence_of :first_name, :last_name, 
                         :if => lambda {|r| r.current_step == "name"}


  def current_step=(value)
    unless (value == "address")
      address.skip_validation = true
    end    
    @current_step = value 
  end    
end

Ответ 2

Как просто назначить его в своем контроллере до вызова participant.valid?:

@participant.address.participant = @participant

Ответ 3

Хотя методы ActiveRecord "validate" очень удобны, вам нечего мешать "перевернуть", возможно, используя before_save hooks. Вы можете заменить валидатор validates_presence_of на Address на before_save, который выполняет проверку только при определенных условиях. Тогда accepts_nested_attributes_for предположительно не увидит его.