控制器中的问题/混合 - 变量/方法可见性问题

时间:2016-01-01 06:31:15

标签: ruby-on-rails

所以,我有几个控制器可以处理模型实例列表,一旦我完成了一个控制器,我就决定将它们全部用于重用代码。

module ListController
  extend ActiveSupport::Concern
  #code
end

但它带来了几个问题。

首先,我需要这个控制器来处理不同的资源。例如:

module ListController
  extend ActiveSupport::Concern
  included do
    doll =  self.name.to_s.match(/^(\w+)ListController/)[1]
    @resource = doll.downcase
    @klass = doll.singularize.constantize
    define_method("new_#{@resource}_list")  do
      if appropriate_quantity?
        quantity=params[:quantity].to_i
        array = Array.new(quantity) do
          @klass.new
        end
        instance_variable_set("@#{@resource}", array)
      elsif invalid_entry_cookie?
        invalid_entries_from_redis(@klass)
      else
        redirect_to :back
      end
    end
  end
end

因此,当包含模块时,我得到控制器的名称,在ListController之前找到部分,并且根据我自己的约定,它引导我到需要的模型和资源:

doll =  self.name.to_s.match(/^(\w+)ListController/)[1]#=>Students
@resource = doll.downcase #=>students
@klass = doll.singularize.constantize #=>Student

似乎很好。但

1)模块本身没有看到实例变量。因此,@resource@klass会在行define_method之后放松它的可见性,而一切都失去了它的意义。我不能使模块足够灵活,可以重复使用,而这些变量在所有包含的块中都是可见的。溶液

2)包含,我是否将@resource@klass传递给每个控制器?我不喜欢这个,因为他们不需要那里。我想避免它。

1 个答案:

答案 0 :(得分:0)

1)您可以使用before_action过滤器来设置这些实例变量,如下所示:

module ListController
  extend ActiveSupport::Concern

  included do

    # Set instance vars in the current class
    init_proc = Proc.new do |c|
      doll =  c.class.name.match(/^(\w+)ListController/)[1]
      c.instance_variable_set(:@resource, doll.downcase)
      c.instance_variable_set(:@klass, doll.singularize.constantize)
    end

    # Run the above proc before each page load this method is declared in
    before_action(init_proc)

    # Make @resource and @klass available right now
    init_proc.call(self)

    define_method("new_#{@resource}_list")  do
      if appropriate_quantity?
        quantity=params[:quantity].to_i
        array = Array.new(quantity) do
          @klass.new
        end
        instance_variable_set("@#{@resource}", array)
      elsif invalid_entry_cookie?
        invalid_entries_from_redis(@klass)
      else
        redirect_to :back
      end
    end
  end
end

2)您可以在ApplicationController中加入此类问题,以避免包含在任何地方。