Как проверить вложенный объект модели в зависимости от состояния родительского объекта?
Я пишу магическую форму в рельсах; например несколько входных страниц для одного объекта модели.
Основы моего подхода - это те, которые описаны в 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 - обновлено, чтобы удалить дополнительную информацию и перейти к основной проблеме
Ответы
Ответ 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
предположительно не увидит его.