2011-12-12 108 views
0

我有这样的模式:红宝石EVAL重构

Class User 
    has_many :comments 
    # have field 'name' in DB 
end 

Class Comment 
    belongs_to :user 
end 

,我已经非常复杂,非常困难的理解管理员后台,它可以获取所有车型,并允许从管理界面控制它。它获取所有关联并用evals处理它。

而这样的eval正常工作:

eval("comment." + o[0][:object]) 

其中o [0] [:对象] = “user.name”

但我想要做它没有EVAL。这种方法的工作原理,但它不是很普遍:

comment.send("user").send("name") 

而在实际的代码看起来很丑陋:

(o[0][:object].split(".").count < 2) ? h(object.send(o[0][:object])) : h(object.send(o[0][:object].split(".")[0]).send(o[0][:object].split(".")[1])) 

那么,什么是让EVAL的univesality这样contructions最好的方式,如果我想显示更多嵌套呼叫,如:

comment.user.first_friend.haters.count 

???

+0

命名作用域在创建复杂的查找器时非常流行。至于重构eval,看起来你可能可以用单表继承来完成它。 – CambridgeMike

+1

它看起来很丑,因为你在内联 - 在现实生活中,你会编写一个方法,递归或迭代,调用当前对象的下一个方法,设置当前对象,并继续执行直到完成或发生错误。除此之外,你的目的并不清楚 - 你是否试图避免为每个模型写一个管理页面? –

回答

2

我不确定为什么你不想在这种情况下使用eval。有时候这是最好的解决方案。

在这里,您可以简单地这样做:

o[0][:object].split('.').reduce(object){|method, obj| obj.send method } 
+0

这里是_shortest_解决方案(绝对不是最好的),但即使这是因为他有另一种代码味道:o [0] [:object]'的内容。那是怎么做的(方法名称以点分隔)到达那里? 'eval'似乎是这里最少的问题。 –

+0

@MladenJablanović当然,这个问题是缺少的上下文。我不想在这里猜测OP。 –

+0

顺便说一句,它似乎也可以工作:'o [0] [:object] .split('。')。reduce(object,:send)' –

0
这个

什么?

class Object # or just ActiveRecord::Base 
    def multiple_send(methods) 
    first_method, remaining_methods = methods.split(".", 2) 
    ret = __send__(first_method) # I use __send__ to prevent from classes overwriting send() method 

    remaining_methods.nil? ? ret : ret.multiple_send(remaining_methods) 
    end 
end 

然后你可以写一些像comment.multiple_send("user.name")