Rails关注:带有块的类方法

时间:2014-09-22 22:06:12

标签: ruby-on-rails ruby metaprogramming

我正在尝试编写使用代码块的类方法 my_method (如验证)。

模型包含下一个代码:

class Model < ActiveRecord::Base
  include Usable
  my_method :arg_1, :arg_2

  my_method do |model|
    # just for example 
    if model.attribute.present?
      :arg3
    else
      :arg4
    end
  end
  #...
end

my_method 是关注定义的类方法:

module Usable
  extend ActiveSupport::Concern

  # instance methods
  def instance_method
    self.class.display_attrs
  end
  # ...

  module ClassMethods
    #  class methods
    def display_attrs
      @attrs_for_display ||= []
    end

    def my_method(*attr_names, &block)
      attr_names.each do |attr|
        attr_data = { attr: attr }
        display_attrs << attr_data
      end

      display_attrs << { attr: block} if block_given? 
    end
  end
end

实例方法@ model.instance_method在 my_method 直接放入my_method :arg_1, :arg_2

的参数时工作正常
> Model.last.instance_method
=> [{:attr=>:arg_1}, {:attr=>:arg_2}]

但当 my_method 使用块my_method {:arg_3}

时, instance_method 会返回一个Proc对象
> Model.last.instance_method
=>[{:attr=>   #<Proc:0x00 ... >}]

如何根据实例状态输入 my_method 参数?例如,@model.instance_method应该返回:arg_3 if model.attribute.present?

1 个答案:

答案 0 :(得分:1)

问题已通过call method解决。 我重写了instance_method如下:

  def instance_method
    class_attrs = self.class.display_attrs.map { |n| n[:attr] }
    class_blocks = self.class.display_attrs.map { |n| n[:block].call(self) if n[:block] }
    (class_attrs + class_blocks).compact!
  end

  module ClassMethods
  #...
       display_attrs << { block: block} if block_given?
  #...
  end