Как проверить вложенный объект модели на основе состояния родительского объекта? - PullRequest
22 голосов
/ 12 мая 2011

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

Основы моего подхода описаны в многоступенчатой ​​форме 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

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

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

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

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

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

РЕДАКТИРОВАТЬ - обновлено, чтобы удалить дополнительную информацию и перейти к основной проблеме

Ответы [ 3 ]

18 голосов
/ 24 января 2012

Добавьте виртуальный атрибут в модель 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
0 голосов
/ 27 января 2012

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

0 голосов
/ 13 мая 2011

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

@participant.address.participant = @participant
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...