撤消在rendering_controller上设置的实例变量(render_anywhere gem)

时间:2016-04-29 15:56:27

标签: ruby-on-rails ruby ruby-on-rails-4 rubygems

这个问题的具体用例可能会引起github问题,但我的问题比你所看到的具体用例更广泛,所以请耐心等待!

我在项目中使用render_anywhere gem,我发现需要撤销在下一次迭代发生之前在循环内设置的实例变量(使用{{的对象)的情况1}}存在于循环外部,因此变量保留在范围内。

我宁愿避免在可能的情况下为循环的每次迭代重新初始化对象。

set_instance_variable方法的工作原理如下(摘自rubydoc):

# File 'lib/render_anywhere.rb', line 20

def set_instance_variable(var, value)
  rendering_controller.class_eval do
    attr_accessor :"#{var}"
  end
  rendering_controller.public_send("#{var}=", value)
end

所以我想我需要使用this answer中描述的方法中的某些内容删除attr_accessor

undef :"#{var}"
undef :"#{var}="

所以我的问题确实是双重的:

  1. 上面是设置实例变量后从rendering_controller删除属性读/写方法的最佳方法吗?
  2. attr_accessor执行undef无法清理的其他任何内容'

1 个答案:

答案 0 :(得分:0)

attr_accessor是一个“宏”,它只是为具有相同名称的ivar定义getter和setter方法:

# This line...
attr_accessor :hello

# ...is equivalent to these
def hello
  @hello
end

def hello=(value)
  @hello = value
end

因此,您需要撤消set_instance_variable代码的效果:

  1. 创建getter var
  2. 创建setter var=
  3. 使用@var参数
  4. 中的值初始化ivar value

    请注意set_instance_variable方法在控制器实例上下文中执行所有这些操作,而不是控制器类上下文(尽管令人困惑class_eval)。

    您必须执行以下操作才能撤消上述所有操作:

    def unset_instance_variable(var)
      rendering_controller.remove_instance_variable("@#{var}") if instance_variable_defined?("@#{var}")
      rendering_controller.class_eval { remove_method(var) } if rendering_controller.respond_to?(var)
      rendering_controller.class_eval { remove_method("#{var}=") } if rendering_controller.respond_to?("#{var}=")
    end  
    

    如果您想避免猴子修补,请考虑将rendering_controller作为参数发送此方法。