多个字段的单个虚拟属性定义

我想知道是否有办法设置虚拟属性,以便它可以处理多个字段/变量。

基本上,我的模型中有几个不同的整数列(收入,税收),每个我需要检查表单提交时,并删除非法字符,我通过设置虚拟属性并使用tr来删除剥去角色。

 def flexible_income income end def flexible_income=(income) self.income = income.tr('$ ,', '') unless income.blank? end 

然后我应该在控制器中设置强参数:

 params.required(:tax).permit(:flexible_income, :flexible_taxes) 

问题是我有很多字段(不仅仅是我上面列出的两个字段),因此对于每个字段,(其中许多只需要检查完全相同的非法字符)我必须使用新的虚拟属性和基本上只是重复相同的代码:

 def flexible_taxes taxes end def flexible_taxes=(taxes) self.taxes = taxes.tr('$ ,', '') unless taxes.blank? end 

反正只是为许多不同的字段设置一个共同的共享属性,同时仍能设置强参数?

您始终可以使用元编程来动态生成所有这些重复的代码。

 module Flexible FLEXIBLE_ATTRIBUTES.each do |attr| define_method("flexible_#{attr}") do self.send(attr) end define_method("flexible_#{attr}=") do |val| self.send("#{attr}=", val.tr('$ ,', '')) unless val.blank? end end end 

现在在您的类中包含此模块并定义FLEXIBLE_ATTRIBUTES

 class MyModel FLEXIBLE_ATTRIBUTES = [:income, :taxes] #...... include Flexible end 

现在我还没有测试过这段代码,但是它应该以最小的重复性来完成你正在寻找的东西。 它还将Flexible方法创建逻辑分离到模型本身之外。 如果需要,它还允许您在其他类中重用此模块。

您可以利用ruby的元编程define_method

为列的列表定义虚拟属性

 ['income','taxes'...].each do |attr| define_method("flexible_#{attr}") do |arg| eval "#{attr}" end define_method("flexible_#{attr}=") do |arg| eval "self.#{attr} = #{arg}.tr('$ ,', '') unless #{arg}.blank?" end end 

参考:

https://rubymonk.com/learning/books/2-metaprogramming-ruby/chapters/25-dynamic-methods/lessons/72-define-method

http://apidock.com/ruby/Module/define_method

http://apidock.com/ruby/Kernel/eval