所以,我有几个控制器可以处理模型实例列表,一旦我完成了一个控制器,我就决定将它们全部用于重用代码。
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
传递给每个控制器?我不喜欢这个,因为他们不需要那里。我想避免它。
答案 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
中加入此类问题,以避免包含在任何地方。