Ответ 1
Начало этого кодового пути кажется правильным:
https://github.com/rails/rails/blob/d90b4e2/activerecord/lib/active_record/base.rb#L1811
Это было сложно найти! Надеюсь, это поможет вам найти то, что вам нужно.
Когда мы используем <%= f.datetime_select :somedate %>
в форме, он генерирует HTML как:
<select id="some_date_1i" name="somedate1(1i)"> #year
<select id="some_date_2i" name="somedate1(2i)"> #month
<select id="some_date_3i" name="somedate1(3i)"> #day
<select id="some_date_4i" name="somedate1(4i)"> #hour
<select id="some_date_5i" name="somedate1(5i)"> #minute
При отправке этой формы принимаются значения somedate1(<n>i)
:
{"date1(1i)"=>"2011", "date1(2i)"=>"2", "date1(3i)"=>"21", "date1(4i)"=>"19", "date1(5i)"=>"25"}
Как я могу преобразовать это в объект DateTime? Я мог бы написать свой собственный метод, чтобы сделать это, но так как Rails уже может выполнить преобразование, мне было интересно, могу ли я назвать этот метод Rails, чтобы сделать это для меня.
Проблема в том, что я не знаю, где искать этот метод.
Ps. Я в конечном счете пытаюсь решить эту другую проблему У меня есть, и этот вопрос является первым шагом в попытке найти решение этой другой проблемы.
Начало этого кодового пути кажется правильным:
https://github.com/rails/rails/blob/d90b4e2/activerecord/lib/active_record/base.rb#L1811
Это было сложно найти! Надеюсь, это поможет вам найти то, что вам нужно.
Это преобразование происходит в ActiveRecord при сохранении вашей модели.
Вы можете обойти это примерно так:
somedate = DateTime.new(params["date1(1i)"].to_i,
params["date1(2i)"].to_i,
params["date1(3i)"].to_i,
params["date1(4i)"].to_i,
params["date1(5i)"].to_i)
DateTime::new
является псевдонимом DateTime::civil
(ruby-doc)
Привет, я добавил следующее на ApplicationController и сделал это преобразование.
#extract a datetime object from params, useful for receiving datetime_select attributes
#out of any activemodel
def parse_datetime_params params, label, utc_or_local = :local
begin
year = params[(label.to_s + '(1i)').to_sym].to_i
month = params[(label.to_s + '(2i)').to_sym].to_i
mday = params[(label.to_s + '(3i)').to_sym].to_i
hour = (params[(label.to_s + '(4i)').to_sym] || 0).to_i
minute = (params[(label.to_s + '(5i)').to_sym] || 0).to_i
second = (params[(label.to_s + '(6i)').to_sym] || 0).to_i
return DateTime.civil_from_format(utc_or_local,year,month,mday,hour,minute,second)
rescue => e
return nil
end
end
Кто-то здесь предложил решение использовать DateTime.new, но это не будет работать в Postgresql. Это сохранит запись как есть, то есть, поскольку она была вставлена в форму, и, таким образом, она не будет сохраняться в базе данных как время utc, если вы используете "timestamp without timezone". Я потратил часы, пытаясь разобраться в этом, и решение заключалось в том, чтобы использовать Time.new, а не DateTime.new:
datetime = Time.new(params["fuel_date(1i)"].to_i, params["fuel_date(2i)"].to_i,
params["fuel_date(3i)"].to_i, params["fuel_date(4i)"].to_i,
params["fuel_date(5i)"].to_i)
Придется сделать что-то очень похожее, и в итоге использовал этот метод:
def time_value(hash, field)
Time.zone.local(*(1..5).map { |i| hash["#{field}(#{i}i)"] })
end
time = time_value(params, 'start_time')
Смотрите также: TimeZone.local
У меня возникла проблема с Rails 4. Оказалось, что я забыл добавить разрешенные параметры к моему контроллеру:
def event_params
params.require(:event).permit(....., :start_time, :end_time,...)
end
Это метод, который я использую - он возвращает удаленные ключи как новый хэш.
class Hash
def delete_by_keys(*keys)
keys.each_with_object({}) { |k, h| h[k] = delete(k) if include? k }
end
end