* _attributes = () не проходит проверку для вложенного атрибута - PullRequest
1 голос
/ 20 мая 2011

Исходное название: before_validation при обновлении - ошибка не обрабатывается должным образом

Я пытаюсь выяснить, как обрабатывать проверку вложенного объекта, особенно при обновлении.

Мой родительский класс, который обрабатывает вложенные атрибуты.

meeting.rb

has_many :proposed_times, :dependent => :destroy, :inverse_of => :meeting
validates_associated :proposed_times
accepts_nested_attributes_for :proposed_times
...
def proposed_times_attributes=(attributes)
  attributes.each do |key,value|
    value[:timezone] = timezone
    if value[:id]
      p = ProposedTime.find(value[:id])
      value.delete(:id)
      p.update_attributes(value)
    else
      self.proposed_times << ProposedTime.new(value)
    end
  end
end

Класс, который я пытаюсь проверить, ниже. В основном мне нужно подтвердить, что дата в будущем. И я создаю свой initial_at с помощью before_validation метода. Так что я не уверен, как справиться со случаем, когда (A) он не может правильно построить дату (в случае, когда пользователь удаляет дату, мне нужно сказать пользователю, чтобы заполнить ее) (B) Если я это сделаю создайте его, затем он потерпит неудачу при сохранении, я не знаю, как заставить его вернуться к представлению для исправления информации.

proposed_times.rb

belongs_to :meeting, :inverse_of => :proposed_times
validate :future_enough
before_validation :construct_starting_at
...
def future_enough
  unless starting_at && starting_at >= (Time.now + 15.minutes)
    errors.add(:not_far_enough_out, "msg not used but: starting_at isn't far enough out")
  end
end

def construct_starting_at
  if date.present? && time.present? && timezone.present?
    begin
      d = Time.parse(date)
      self.starting_at = Time.zone.parse("#{d.year}-#{d.month}-#{d.day} #{time.hour}:#{time.min}:00 #{timezone}")
    rescue
      self.starting_at = nil
    end
  end
end

Вот вид, который я использую. Я знаю, что это не лучший способ справиться с этой функциональностью, но я работаю с тем, что у меня есть ... Все, что я делаю, перенаправляет на thank_you. Я не уверен, почему это не сбой при сохранении.

meeting_controller.rb

def propose_times
  @consultation = Consultation.find(params[:id])
  @user = current_user

  # If this is coming second time around with data to save
  if request.put?
    @consultation.attributes = params[:consultation]
    if @consultation.save
      redirect_to thank_you_path
    else
      render :layout => "simple"
    end
  else
    render :layout => "simple"
  end
end

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

Обновление : Таким образом, используя предложение @ Aditya о validates_associated, оно по-прежнему не проверяет только обновленные данные. Обновленные времена, которые я вставляю, проверяются ... но, поскольку они недействительны, они не сохраняются, а затем снова проверяются (со старыми данными), а затем проходит / не проходит проверку и отображаются предупреждения для этих дат .

Что мне не хватает?

Обновление 2 : я добавил кучу операторов p, чтобы увидеть порядок событий, и если я опущу validated_associated, он будет проверен только один раз, но по какой-то причине сама конференция сохраняет хорошо, и поэтому он перенаправляет, чтобы поблагодарить вас. Но если я оставлю это, он проверяет дважды, отсюда и проблемы. Так почему же это проверка первого (или второго) раза и как мне это остановить?

Обновление 3 : Хорошо, поэтому я удалил свою функцию proposed_times_attributes= и добавил в нее часовой пояс. Это решило проблему (вместе с методом @ Aditya). Хотелось бы знать, как заставить его работать с таким методом. Я пробовал различные другие комбинации наличия / отсутствия validates_associated, accepts_nested_attributes_for и определения этой функции.

ТАК, если вы сталкиваетесь с этим и знаете, как написать proposed_times_attributes=, чтобы проверка работала, пожалуйста, дайте мне знать. Мне нужно иметь возможность указать часовой пояс в proposed_times_attributes=, потому что я хотел бы посмотреть поставить один флажок выбора часового пояса для всех предлагаемых времен. Я хотел бы, чтобы был способ вызвать super () внутри метода *_attributes=().

Ответы [ 2 ]

1 голос
/ 23 мая 2011

Наконец-то разобрался. Таким образом, вы можете создать метод типа super(), вызвав assign_nested_attributes_for_collection_association или assign_nested_attributes_for_one_to_one_association. Но вам также необходимо вызвать accepts_nested_attributes_for, чтобы установить некоторые параметры для этих методов (нажмите на имя функции, чтобы увидеть документацию для каждого из них).

accepts_nested_attributes_for :advisor, :client, :proposed_times
...
def proposed_times_attributes=(attributes)
  attributes.each do |key,value|
    value[:timezone] = client.timezone
  end
  assign_nested_attributes_for_collection_association(:proposed_times, attributes)
end
0 голосов
/ 23 мая 2011

@ RyanJM

Вам не нужно вручную проверять дочерние дочерние объекты, если вы используете следующее

meeting.rb

validates_associated :proposed_times

при условии, что у вас уже есть следующая ассоциация в вашем meeting.rb

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