我有这个型号:
class Event < Registration
serialize :fields, Hash
Activities=['Annonce', 'Butiksaktivitet', 'Salgskonkurrence']
CUSTOM_FIELDS=[:activity, :description, :date_from, :date_to, :budget_pieces, :budget_amount, :actual_pieces, :actual_amount]
attr_accessor *CUSTOM_FIELDS
before_save :gather_fields
after_find :distribute_fields
private
def gather_fields
self.fields={}
CUSTOM_FIELDS.each do |cf|
self.fields[cf]=eval("self.#{cf.to_s}")
end
end
def distribute_fields
unless self.fields.nil?
self.fields.each do |k,v|
eval("self.#{k.to_s}=v")
end
end
end
end
我觉得这可以做得更短更优雅。有没有人有想法?
顺便说一句。谁能告诉我CUSTOM_FIELDS前面的星号是什么?我知道它在方法定义中的作用(def foo(* args))但不在这里......
答案 0 :(得分:3)
首先关闭:从不10000000000.times { puts "ever" }
使用eval
,当您不知道自己在做什么时。它是红宝石世界的核弹,它可以在广泛的区域内造成破坏,在整个代码中引起辐射中毒的类似症状。只是不要。
考虑到这一点:
class Event < Registration
serialize :fields, Hash
Activities = ['Annonce', 'Butiksaktivitet', 'Salgskonkurrence']
CUSTOM_FIELDS = [:activity,
:description,
:date_from,
:date_to,
:budget_pieces,
:budget_amount,
:actual_pieces,
:actual_amount] #1
attr_accessor *CUSTOM_FIELDS #2
before_save :gather_fields
after_find :distribute_fields
private
def gather_fields
CUSTOM_FIELDS.each do |cf|
self.fields[cf] = send(cf) #3
end
end
def distribute_fields
unless self.fields.empty?
self.fields.each do |k,v|
send("#{k.to_s}=", v) #3
end
end
end
end
现在有一些注意事项:
*CUSTOM_FIELDS
的{{1}}使用了所谓的“splat运算符”。通过以这种方式调用它,attr_accessor
数组的元素将作为单独的参数传递给CUSTOM_FIELDS
方法而不是作为一个(数组本身)attr_accessor
方法调用我们不知道编程期间名称的方法,而不是邪恶的send
。除此之外,我找不到任何重构此代码的内容。
答案 1 :(得分:1)
我同意以前的海报。此外,我可能会将gather_fields和distribute_fields方法移动到父模型,以避免在每个子模型中重复代码。
class Registration < ActiveRecord::Base
...
protected
def gather_fields(custom_fields)
custom_fields.each do |cf|
self.fields[cf] = send(cf)
end
end
def distribute_fields
unless self.fields.empty?
self.fields.each do |k,v|
send("#{k.to_s}=", v)
end
end
end
end
class Event < Registration
...
before_save :gather_fields
after_find :distribute_fields
private
def gather_fields(custom_fields = CUSTOM_FIELDS)
super
end
end
答案 2 :(得分:0)
你可以用发送电话取代两个人:
self.fields[cf] = self.send(cf.to_s)
self.send("#{k}=", v)
“#{}”执行to_s,因此您不需要k.to_s
作为一个常数的活动应该是活动。
答案 3 :(得分:0)
对于那个星号*,请查看此帖子:What is the splat/unary/asterisk operator useful for?
Activities=['Annonce', 'Butiksaktivitet', 'Salgskonkurrence']
可以写成:ACTIVITIES = %w(Annonce, Butiksaktivitet, Salgskonkurrence).freeze
因为你要定义一个常量。
def distribute_fields
unless self.fields.empty?
self.fields.each do |k,v|
send("#{k.to_s}=", v) #3
end
end
end
可以写成一个班轮:
def distribute_fields
self.fields.each { |k,v| send("#{k.to_s}=", v) } unless self.fields.empty?
end
Ryan Bigg给出了一个很好的答案。