我想知道是否有办法设置虚拟属性,以便它可以处理多个字段/变量。
基本上,我的模型中有几个不同的整数列(收入、税收),对于它们中的每一个,我需要检查表单何时提交,并删除非法字符,我是通过设置虚拟属性并使用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
现在我还没有测试过这段代码,但它应该以最小的重复性完成你正在寻找的事情。它还将灵活方法创建逻辑与模型本身分开。如果需要,它还允许您在其他类中重用此模块。
利用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