Пытаюсь установить переменную в before_validation, но это не работает

#ruby-on-rails #ruby-on-rails-3 #update-attributes

#ruby-on-rails #ruby-on-rails-3 #обновить-атрибуты

Вопрос:

Итак, на мой взгляд, я использую календарь для выбора дня и выпадающие списки для выбора времени. Поэтому я использую before_validation метод для объединения:

proposed_time.rb

 before_validation :construct_starting_at

def construct_starting_at
  d = Time.parse(date)
  puts "************** construct_starting_at BEGIN *****************"
  puts "DATE: #{d}"
  puts "Time: #{time}"
  puts "Timezone: #{timezone}"
  puts "construct_starting_at :: #{d.year}-#{d.month}-#{d.day} #{time.hour}:#{time.min}:00 #{timezone}"
  if date.present? amp;amp; time.present? amp;amp; timezone.present?
    starting_at = Time.zone.parse("#{d.year}-#{d.month}-#{d.day} #{time.hour}:#{time.min}:00 #{timezone}")
  end
  puts "starting_at: #{starting_at}"
  puts "************** construct_starting_at END *****************"
end 
  

И это работает просто отлично, когда я создаю объект, но не когда я его обновляю.

журнал

 ************** construct_starting_at BEGIN *****************
DATE: Fri Jun 03 00:00:00 -0500 2011
Time: Thu May 19 23:00:00 UTC 2011
Timezone: (GMT-05:00) Eastern Time (US amp; Canada)
construct_starting_at :: 2011-6-3 23:0:00 (GMT-05:00) Eastern Time (US amp; Canada)
starting_at: 2011-06-04 00:00:00 -0400
************** construct_starting_at END *****************
  

Но когда я использую ее для обновления, она полностью теряется и возвращается к тому, что было. Это заставляет меня чувствовать, что на самом деле она не сохраняется. Итак, чтобы помочь объяснить контекст в следующем, у меня есть ProposedTime объект, и он является дочерним для Consultation (в каждой консультации предлагается 3 раза), который также имеет accepts_nested_attributes_for :proposed_times :

консультация.rb

 def proposed_times_attributes=(attributes)
  puts "$$$$$$$$$$$$$$ proposed_times_attributes $$$$$$$$$$$$$$$$"
  attributes.each do |key,value|
    value[:timezone] = timezone
    if value[:id]
      puts "Updating #{value[:id]}"
      p = ProposedTime.find(value[:id])
      value.delete(:id)
      unless p.update_attributes(value)
        puts "@@@@@@@@@@@@@@@@@ ERROR @@@@@@@@@@@@@@@"
        error.add(:proposed_times, "something is wrong")
      end
      puts "-- starting_at:  #{p.starting_at}"
    else
      puts "Creating a new proposed time"
      proposed_times << ProposedTime.new(value)
    end
  end
  puts "$$$$$$$$$$$$$$ proposed_times_attributes $$$$$$$$$$$$$$$$"
end
  

журнал

 ...
Updating 18
************** construct_starting_at BEGIN *****************
DATE: Fri Jun 03 00:00:00 -0500 2011
Time: Thu May 19 23:00:00 UTC 2011
Timezone: (GMT-05:00) Eastern Time (US amp; Canada)
construct_starting_at :: 2011-6-3 23:0:00 (GMT-05:00) Eastern Time (US amp; Canada)
starting_at: 2011-06-04 00:00:00 -0400
************** construct_starting_at END *****************
-- starting_at:  2011-06-01 06:00:00 -0400
  

Я думал, что это могло вызвать ошибку в update_attributes, но, похоже, это не так. Есть идеи?

Ответ №1:

Я не грокнул это полностью, но я просто использую простые вещи — я думаю, вы хотите, чтобы starting_at не был локальной переменной, но фактически устанавливал атрибут starting_at вашего объекта:

 self.starting_at = Time.zone.parse("#{d.year}-#{d.month}-#{d.day} #{time.hour}:#{time.min}:00 #{timezone}")
  

Ключевым битом является self. , чтобы действительно убедиться, что атрибут установлен, а не какая-то локальная переменная с тем же именем, которая существует только в этом методе.

Комментарии:

1. Есть предложения узнать, когда использовать self. , а когда нет необходимости? Или это просто лучшая практика использовать ее постоянно? Спасибо за ответ!

2. Используйте это при настройке переменных экземпляра / объекта. Если вы вызываете методы или получаете значения переменных экземпляра / объекта, то self не требуется.