13

高度以英寸为单位存储在数据库中。

然而,英尺和英寸需要它们自己的单独输入,格式为:

Height: [_______] feet [_______] inches

所以我使用了虚拟属性,并让它工作。这是我的模型的简化版本:

class Client < ActiveRecord::Base
  attr_accessible :name, :height_feet, :height_inches

  before_save :combine_height

    def height_feet
      height.floor/12 if height
    end

    def height_feet=(feet)
      @feet = feet
    end

    def height_inches
      if height && height%12 != 0
        height%12
      end
    end

    def height_inches=(inches) #on save?
      @inches = inches
    end

  def combine_height
    self.height = @feet.to_d*12 + @inches.to_d #if @feet.present?
  end

end

_form部分使用 simple_form :

<%= simple_form_for(@client) do |f| %>
  <ul>
    <%= f.error_notification %>
    <%= f.input :name %>
    <%= f.input :weight %>
    <li>
      <%= f.input :height_feet, :label => 'Height', :wrapper => false %>
      <span>feet</span>
      <%= f.input :height_inches, :label => false, :wrapper => false %>
      <span>inches</span>
    </li>
    <%= f.error :base %>
  </ul>
    <%= f.button :submit %>
<% end %>

这行得通。不过这是不理想的。

我想把它干掉并创建一个自定义输入组件,这样我就可以为表单添加高度<%= f.input :height, as: :feet_and_inch %>- 因此任何其他遵循相同模式的输入,例如<%= f.input :wingspan, as: :feet_and_inch %>.

我已经尝试过自定义组件,但我无法显示两个输入 - 而且我不确定将“转换”逻辑从英尺和英寸转换为英寸(同样从英寸返回到英尺和英寸)。

4

2 回答 2

6

据我所知,除了渲染到自定义输入之外,您不能真正移动任何东西。提交表单后,SimpleForm 不会被调用,因此它不会以任何方式真正干扰值。我很想错了,因为我过去也需要它。无论如何,这是一个将转换逻辑保留在模型中的版本。

自定义 SimpleForm 输入:

# app/inputs/feet_and_inch_input.rb
class FeetAndInchInput < SimpleForm::Inputs::Base
  def input
    output           = ""
    label            = @options.fetch(:label) { @attribute_name.to_s.capitalize }

    feet_attribute   = "#{attribute_name}_feet".to_sym
    inches_attribute = "#{attribute_name}_inches".to_sym

    output << @builder.input(feet_attribute, wrapper: false, label: label)
    output << template.content_tag(:span, " feet ")
    output << @builder.input(inches_attribute, wrapper: false, label: false)
    output << template.content_tag(:span, " inches ")

    output.html_safe
  end

  def label
    ""
  end
end

表格。请注意,我没有将<li>标签放在自定义输入中,我认为这种方式更灵活,但可以随意更改。

# app/views/clients/_form.html.erb
<li>
  <%= f.input :height, as: :feet_and_inch %>
</li>

所有这一切都依赖于这样一个事实,即对于每个height属性,您还拥有height_feetheight_inches属性。

现在对于模型,老实说,我不确定这是否是要走的路,也许有人可能会想出一个更好的解决方案,但它是这样的:

class Client < ActiveRecord::Base
  attr_accessible :name

  ["height", "weight"].each do |attribute|
    attr_accessible "#{attribute}_feet".to_sym
    attr_accessible "#{attribute}_inches".to_sym

    before_save do
      feet  = instance_variable_get("@#{attribute}_feet_ins_var").to_d
      inches = instance_variable_get("@#{attribute}_inches_ins_var").to_d

      self.send("#{attribute}=", feet*12 + inches)
    end

    define_method "#{attribute}_feet" do
      value = self.send(attribute)
      value.floor / 12 if value
    end

    define_method "#{attribute}_feet=" do |feet|
      instance_variable_set("@#{attribute}_feet_ins_var", feet)
    end

    define_method "#{attribute}_inches=" do |inches|
      instance_variable_set("@#{attribute}_inches_ins_var", inches)
    end

    define_method "#{attribute}_inches" do
      value = self.send(attribute)
      value % 12 if value && value % 12 != 0
    end
  end
end

它基本上做同样的事情,但动态地定义了方法。您可以在顶部看到您希望为其生成这些方法的属性列表。

请注意,所有这些都没有经过彻底的测试,可能会杀死你的猫,但希望能给你一些想法。

于 2012-12-28T18:05:36.093 回答
2

我的拙见是,如果用户只在一个字段中输入数据,您将提供更好的用户体验。以下是我的担忧:

假设您使用的是有限范围内的高度(可能是人类的高度),您可以编写一个验证来检测用户输入的内容 - 英寸或英尺。然后你可以做一个验证链接(或者更好的按钮)询问输入是否是它的意思(检测到英寸或英尺)。

所有这些(包括尺寸转换,只是英寸 -> 英尺)都可以在 javascript 中完成,您可以通过 Ajax 调用获取当前尺寸,避免重新加载页面的整个代码。

编辑:我发现了一个与复杂输入相关的有趣观点。另一个关于用户交互的有用资源,用英尺和英寸填写表格。

你的问题真的很有趣,我很想看看你选择的解决方案。

于 2012-12-21T12:03:04.317 回答