【问题标题】:Convert hours & minutes to seconds before saving a record在保存记录之前将小时和分钟转换为秒
【发布时间】:2015-10-21 13:03:33
【问题描述】:
我对 Rails 还是很陌生。到目前为止,我所有的表单元素都直接映射到它们底层的 Rails 模型对应物。在我目前的情况下,这是不可能的。
我的模型有一个 event_duration 字段,它以秒为单位存储持续时间(integer 类型)。
在我的表单中,虽然我想要两个文本字段:hours 和 minutes。提交表单后,我想将这些值转换为秒并将结果值存储在模型中。
完成此任务的最佳方法是什么? (提前谢谢)
【问题讨论】:
标签:
ruby-on-rails
forms
model
【解决方案1】:
您可以在控制器中创建一个“挂钩”以在创建/更新记录之前更新params:
class EventsController < ApplicationController
before_filter :sanitize_durations_in_params, only: [:create, :update]
# ...
def sanitize_durations_in_params
hours = params[:event].delete(:hours).to_i
minutes = params[:event].delete(:minutes).to_i
minutes = minutes + hours * 60
seconds = minutes * 60
params[:event][:event_duration] = seconds
end
end
此代码意味着您的表单中有一个名称为 event[:hours] 的输入和另一个名称为 event[:minutes] 的输入。如果您已经有一个名称为 event[:event_duration] 的输入,它将被覆盖。
【解决方案2】:
您可以在模型中创建虚拟属性:
class Model < ActiveRecord::Base
attr_reader :hours_event_duration, :minutes_event_duration, :use_diff_event_duration_variables
before_save :correct_save_event_duration
def initialize(*args)
@hours_event_duration = @minutes_event_duration = 0
@use_diff_event_duration_variables = false
super
end
...
protected
def correct_save_event_duration
self.event_duration = @hours_event_duration * 1.hour + @minutes_event_duration * 1.minute if @use_diff_event_duration_variables
end
end
并以您的形式:
f.hidden_field :use_diff_event_duration_variables, true
f.text_field :hours_event_duration
f.text_field :minutes_event_duration
【解决方案3】:
实现此目的的另一种方法是所谓的表单对象,它本质上是一个“模拟模型”,您可以将其传递给控制器以代替模型,然后由控制器处理表单呈现和持久性。
这样做的好处是您的控制器中不需要任何逻辑,并且您可以消除模型中令人讨厌的回调。在处理多个模型时,它们在摆脱accepts_nested_attributes_for 陷阱方面也非常出色。
它可能看起来像这样:
# app/forms/event_form.rb
class EventForm
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :duration_hours, :duration_minutes, ... # Event parameters
validates ... # Your validations
def save
if valid?
persist!
else
false
end
end
private
def persist!
event = Event.new(...) # Event parameters
event.event_duration = ((duration_hours * 60) + duration_minutes) * 60
event.save
end
end
通过包含一些ActiveModel 模块,您可以借用一些功能,例如从Hash 初始化和验证。
在你的控制器中:
# app/controllers/events_controller.rb
def new
@event = EventForm.new
end
def create
@event = EventForm.new(event_params).save
end
如果您不想自己滚动,还可以使用 Gem 来创建表单对象,例如 reform。