Rails在ActiveRecord模型上有一个结合“respond_to?”的实例方法吗?并且寄出”?

时间:2013-12-18 15:01:53

标签: ruby-on-rails ruby activerecord

我已经做了一些谷歌搜索,但无济于事。

我的场景是我有一个辅助方法,它采用一些选项,然后通过部分渲染页面上常用的图形元素,通过发送的选项进行调整。这些选项中的大多数具有由助手设置的不同的可覆盖默认值,基于前两个必需参数 - 对象上下文

def my_helper(object, context, options = {})
    defaults = { ... }
    defaults[:foo] = "bar" if object.is_a?(SomeObject)
    defaults[:ping] = "pong" if context.eql?(:some_context)
    ...
    render partial: '/path/to/partial', locals: defaults.merge(options)
end

虽然上下文都很好看,但是我决定放弃查看 object 类,并且在可行的情况下使用respond_to?而不是。我想要避免的是有多个if object.respond_to?(:foo?) && object.foo?,只使用像if object.respond_to_and_send(:foo?)这样的东西,如果对象无法响应该方法,它将返回nil。


更新
我忘了提到这是一个Rails 3.2应用程序,这是一个耻辱,因为在Holger Just's answer中提到的Rails 4中更新的try方法正是我所需要的。

3 个答案:

答案 0 :(得分:5)

您可以像这样使用try

object.try(:foo?)

它将检查object是否响应foo?,如果是,则调用该方法。如果object未对该方法做出响应,try将返回nil

有关详细信息,请参阅the documentation

答案 1 :(得分:0)

object.send(:foo) rescue nil

这应该可以解决问题。小心使用这种技术引入细微的错误。 (例如,如果方法调用本身引发错误,您将获得nil并且实际异常将被隐藏)

答案 2 :(得分:0)

您的问题的答案是否。 UPD:object.try(:foo?)适用于Rails 4,正如 Holger Just 建议的那样。

但是有一些解决方法。其中之一是使用您需要的方法创建一个模块,并使用它扩展您的上下文对象。

module SmartResponder
   def respond_to_and_send(method, *args, &block)
     public_send(method, *args, &block) if respond_to?(method)
   end
end
context = [1,2,3]
context.extend(SmartResponder)

context.respond_to_and_send(:to_s)
# => "[1, 2, 3]"
context.respond_to_and_send(:to_sssss)
# => nil
context.respond_to_and_send(:inject, 100) { |x,y| x+y }
# => 106