Ruby:使用块参数发送define_method

时间:2017-03-29 05:48:44

标签: ruby-on-rails ruby

我尝试做类似这样的事情,其中​​send方法的块有块参数:

  klass.attribute_names.each do |attribute|
    klass.send(define_method("next_by_" + attribute) { object, user = nil
      if user
        klass.joins(:users).where("#{attribute} > ?", object.send(attribute)).where(users: {id: user.id}).first
      else
        klass.where("#{attribute} > ?", object.send(attribute)).first
      end
    })
  end

哪个不是有效的Ruby。这可能吗,如果是这样,最好的方法是什么?

编辑:我意识到保留关键字" class"这里。它仅用于说明目的。我已将其更改为klass以防止进一步混淆。

更多细节,这是整个文件:

module Helpers::ResourceRecordHelper

  # Remove this and call upon the module's methods to include instead to fix performance hit
  def self.included(source)
    define_class_methods(source)
  end

  def define_class_methods(source)
    source.attribute_names.each do |attribute|

      # These defined methods never reach the class
      define_method("next_by_" + attribute) { object, user = nil
        if user
          self.class.joins(:users).where("#{attribute} > ?", object.send(attribute)).where(users: {id: user.id}).first
        else
          self.class.where("#{attribute} > ?", object.send(attribute)).first
        end
      }

      define_method("previous_by_" + attribute) do object, user = nil
        if user
          self.class.joins(:users).where("#{attribute} < ?", object.send(attribute)).where(users: {id: user.id}).last
        else
          self.class.where("#{attribute} < ?", object.send(attribute)).last
        end
      end
    end

    def source.next(object, user = nil)
      source.next_by_id(object, user)
    end

    def source.previous(object, user = nil)
      source.previous_by_id(object, user)
    end
  end

  extend self

end

1 个答案:

答案 0 :(得分:1)

您遇到的问题很少,例如使用保留字,而不是理解self(或者说没有正确理解您的理解)。

source.attribute_names.each do |attribute|
  source.singleton_class.instance_eval do
    define_method('next_by_' + attribute) do |object, user = nil|
      if user
        source.joins(:users)
              .where("#{attribute} > ?", object.public_send(attribute))
              .where(users: { id: user.id })
              .first
      else
        source.where("#{attribute} > ?", object.public_send(attribute)).first
      end
    end
  end
end