如何使用元编程为ruby中的所有类实例创建一个实例变量?

时间:2014-08-27 13:51:48

标签: ruby-on-rails ruby metaprogramming

我是ruby / rails世界的新手,我面对并发出的问题看似微不足道,但对我来说并不容易。

我想要做的是编写一个简单的帮助方法,以帮助保持控制器清洁。此方法将接收符号/字符串,并使用camelized接收的字符串创建实例变量,该字符串将计算为常量/类。

我的尝试重新开始:

class ApplicationController < ActionController::Base

  ...

  protected

  def self.service(name)
    instance_eval do
      instance_variable_set("@#{name.to_s.pluralize}", name.to_s.camelize.constantize)
    end
  end

而且,在我的控制器中:

class UserController < ApplicationController

  service :user

但是当我这样做时,它会在UserController中创建实例变量,而不是UserController.new。所以,我知道出了什么问题,但我无法找到如何做到这一点。

任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

麻烦的是这个方法在类范围内:

  def self.service(name)
    instance_eval do
      instance_variable_set("@#{name.to_s.pluralize}", name.to_s.camelize.constantize)
    end
  end

这意味着它将设置类级别实例变量 - 或类变量(有点)。

如果你想要遵循这种方法,你需要将所有这些存储在一个类或类似的类级别,这可以在实例化类时读出并转换为实例变量。

但是,我不想在控制器上搞乱初始化方法。这不是做事的方式,所以在改变版本时可能会改变班级行为,破坏事物或变得脆弱。

在ApplicationController中,类似于:

class << self
  def service(name)
    @services ||= []
    return @services += name.map(&:to_sym) if name.is_a?(Array)
    @services << name.to_sym
  end

  def service_names
    @services
  end
end

before_action :services

def services
  self.class.service_names.each do |name|
    instance_eval do
      instance_variable_set("@#{name.to_s.pluralize}", name.to_s.camelize.constantize)
    end
  end
end

这是未经测试的。