ruby-on-rails – 将多输入虚拟属性移动到SimpleForm自定义输入组件

高度以英寸存储在数据库中.

然而脚和英寸需要以下形式的自己的个人投入:

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 %>

这个工作.但这不是理想的.

我想DRY这个,并创建一个custom input component,所以我可以添加高度的形式与<%= f.input:height,as::feet_and_inch%> – 因此任何其他输入,遵循相同的模式,as<%= f.input:wingspan,as::feet_and_inch%&gt ;. 我已经尝试过自定义组件,但是我无法得到两个输入显示,而且我不确定哪里是将“转换”逻辑从英尺和英寸放到英寸的最佳位置(同样从英寸回到英尺和英寸).

解决方法

据我所知,除了渲染到自定义输入之外,你不能移动任何东西.一旦表单被提交,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,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_feet和height_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

它基本上是一样的,但动态定义方法.您可以在顶部看到一个属性列表,您希望生成这些方法.

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

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...