输出helper而不是eval的另一种方法

时间:2012-02-22 03:38:37

标签: ruby-on-rails

(@products + @collections + @users + @questions).map do |r|
  @results << {
     :label => ["Product", "Collection", "User"].include?(r.class.name) ? r.name : r.question,
     :category => r.class.name,
     :href => eval("#{r.class.name.downcase}_path(r)")
  }
end

我目前正在寻找是否有办法不在字符串上使用eval将其转换为帮助器。

注意:此代码目前位于控制器中。 Rails 2.3.11

5 个答案:

答案 0 :(得分:1)

您可以尝试这样的事情:

:href => self.send("#{r.class.name.downcase}_path".to_sym, r)

由于我不完全确定这里的背景,所以我不会百分之百地确信这会起作用,但如果这是一个你试图引用的方法,那么自我就是最可能的目标。

答案 1 :(得分:1)

使用benchmarks shown here动态调用方法有3种方法。我总结一下下面的文章:

在ruby中动态调用方法的一种方法是向对象发送消息:

p s.send(:length) #=> 6 
p s.send(:include?,"hi") #=> true

第二种方法是实例化方法对象,然后调用它:

method_object = s.method(:length) 
p method_object.call #=> 6
method_object = s.method(:include?)
p method_object.call('hi')  #=> true

第三种方法是使用eval方法:

eval "s.length" #=> 6
eval "s.include? 'hi'" #=>true

根据基准测试结果,SLOWEST是eval所以我会改用send

#######################################
#####   The results
#######################################
#Rehearsal ----------------------------------------
#call   0.050000   0.020000   0.070000 (  0.077915)
#send   0.080000   0.000000   0.080000 (  0.086071)
#eval   0.360000   0.040000   0.400000 (  0.405647)
#------------------------------- total: 0.550000sec

#          user     system      total        real
#call   0.050000   0.020000   0.070000 (  0.072041)
#send   0.070000   0.000000   0.070000 (  0.077674)
#eval   0.370000   0.020000   0.390000 (  0.399442)

答案 2 :(得分:1)

你应该做的一些事情有所不同,其中一些已被其他答案暗示或明确说明,但我认为这样做的更好:

@results = (@products + @collections + @users + @questions).map do |r|
  {
     :label => r.try(:question) || r.name,
     :category => r.class.model_name.human,
     :href => send(:"#{r.class.model_name.underscore}_path", r)
  }
end
  1. 您无需手动构建结果数组 - 您已使用map,只需将结果分配给@results
  2. 无需进行所有手动工作来确定您是否应该发布问题或名称。您可以给所有这些模型一个to_label方法,这很简单,但假设问题没有使用try和二进制文件的名称,或者只是解决问题的简单方法。 / LI>
  3. 单个单词模型名称很容易转换为显示标题,但是当你最终得到像BedSheet这样的类时,你会希望它显示为“床单”。不妨开始吧。
  4. 同一问题的另一方面是将类名转换为路径/网址帮助方法:您需要bed_sheet_path,而不是bedsheet_path
  5. 使用send而不是eval,如其他答案中所述。不需要使用显式to_sym,因为Ruby支持使用双引号来直接创建符号。
  6. 另一个快速说明,我不知道Rails 2.x是否相同,但是在Rails 3中你不需要使用路径助手链接到模型的实例,因为大多数html帮助器方法都会转换自动(例如link_to 'A Product', @product)。

    瞧。

答案 3 :(得分:1)

使用polymorphic_path

@results = (@products + @collections + @users + @questions).map do |r|
  {
    :label => ["Product", "Collection", "User"].include?(r.class.name) ? r.name : r.question,
    :category => r.class.name,
    :href => polymorphic_path(r)
  }
end

答案 4 :(得分:0)

您可以使用查找表:

class_procs = {
    Product => {
        :path  => lambda { |r| product_path(r) },
        :label => lambda { |r| r.name }
    },
    Collection => {
        :path  => lambda { |r| collection_path(r) },
        :label => lambda { |r| r.name }
    }
    User => {
        :path  => lambda { |r| user_path(r) },
        :label => lambda { |r| r.name }
    },
    Question => {
        :path  => lambda { |r| question_path(r) },
        :label => lambda { |r| r.question }
    }
}

(@products + @collections + @users + @questions).map do |r|
    procs = class_procs[r.class]
    @results << {
        :label    => procs[:label].call(r),
        :category => r.class.name,
        :href     => procs[:path].call(r)
    }
end

如果您的需求变得更加复杂,那么您可以轻松地将每类Hashes转换为单独的类,以防止内部Hashes变得过于庞大和复杂。