2

我想要某种在单独的模块中初始化的单一列表,然后可以包含在控制器中并在控制器类级别进行修改,并在控制器实例级别进行访问。我认为类变量可以在这里工作,但是发生了一些奇怪的事情,它们似乎没有在我的结束类中被初始化。

进一步来说:

我有很多控制器,都包括一些默认功能,在一个模块中。

class BlahController < ApplicationController
  include DefaultFunctionality
end

class FooController < ApplicationController
  include DefaultFunctionality
end

 module DefaultFunctionality 
   def show 
     render 'shared/show'
   end 
   def model
     controller_name
   end
 end

, 例如。这不是实际的代码,但这是目前最多的交互。

我想用其他一些功能(列表的可排序接口)来扩展它,就像这样[注意我希望能够逐个类地交换排序顺序列表功能]:

module DefaultFunctionality
 module Sortable
  def sort_params
    params.slice(:order, :sort_direction).reverse_merge(default_sort_params)
  end
  def default_sort_params
    @@sorts.first
  end
  def set_sorts(sorts = []) #sorts = [{:order => "most_recent", :sort_direction => :desc},...]
     @@sorts = sorts
  end
 end
 include Sortable
 set_sorts([{:order => :alphabetical, :sort_direction => :asc}] #never run?
end

这个想法是为了确保我能够逐个类地交换所有可能的排序集,如下所示:

class FooController < ApplicationController
  include DefaultFunctionality #calls the default set_sorts
  set_sorts([{:order => :most_recent, :sort_direction => :asc}]) 
end

并且还要在视图中建立很好的链接,如下所示,除了我遇到错误。

___/blah/1 => shared/show.html.erb__
<%= link_to("upside down", polymorphic_path(model, sort_params) %><%#BOOOM uninitialized class variable @@sorts for BlahController %>

我认为 class_var 是一个糟糕的调用,但我想不出我还能使用什么。(类实例变量?)

4

3 回答 3

2

当然,类实例变量是要走的路。您实际上很少需要使用类变量。

在具体回答您的问题时,请记住,模块中定义的任何代码仅在加载模块时执行一次,而不是在包含模块时执行。这种区别可能并不明显,尤其是当人们认为“include”等同于“require”时。

你需要的是这样的:

module DefaultFunctionality
  def sort_params
    params.slice(:order, :sort_direction).reverse_merge(default_sort_params)
  end

  def default_sort_params
    @sorts.first
  end

  def sorts=(sorts = nil)
    @sorts = sorts || [{:order => "most_recent", :sort_direction => :desc}]
  end

  def self.included(base_class)
    self.sorts = ([{:order => :alphabetical, :sort_direction => :asc}]
  end
end

捕获包含模块的类的方法是相应地定义 Module.included 。在这种情况下,每次包含此模块时都会调用 set_sorts,并且它位于调用类的上下文中。

我对此进行了一些修改,以包括一些特定的样式更改:

  • 在方法中而不是在声明中声明您的默认值。避免产生难以阅读的长行,或不得不单行否则复杂的数据结构。
  • 在这种情况下,使用将完成工作的类实例变量。
  • 使用 Ruby 风格的 var= mutator 方法而不是 set_var()
于 2010-03-03T20:13:59.293 回答
0

您必须在模块中添加一个included方法才能使其正常工作。

module DefaultFunctionality

 def self.included(base)
   base.include(Sortable)
   set_sorts([{:order => :alphabetical, :sort_direction => :asc}] #never run?
 end

 module Sortable
  # other methods

  def set_sorts(sorts = [{:order => "most_recent", :sort_direction => :desc}])
     @@sorts = sorts
  end
 end 
end
于 2010-03-03T20:16:29.240 回答
0

在注意到@tadman 做出响应之前,我最终使用了一个没有自动包含子模块的类级别实例变量和包含()。

它最终看起来像这样:

class BlahController < ApplicationController
  include DefaultControllerFunctionality
  include DefaultControllerFunctionality::Sortable
end

class FooController < ApplicationController
  include DefaultControllerFunctionality
  include DefaultControllerFunctionality::Sortable
  sorts=([{:order => :most_recent, :sort_direction => :desc}])
end

在控制器中,在 /lib 下

lib/default_controller_functionality.rb

 module DefaultFunctionality 
   def show 
     render 'shared/show'
   end 
   def model
     controller_name
   end
 end

lib/default_controller_functionality/sortable.rb

 module DefaultControllerFunctionality
   module Sortable
    def self.included(base)
      base.helper_method :sort_params
      base.class_eval <<-END
          @sorts=[]
          class << self; attr_accessor :sorts end
       END
       #this line ^ makes it so that the module 
       #doesn't work when included in any other 
       #module than the class you want @sorts to end up in. 
       #So don't include(Sortable) in DefaultControllerFunctionality and expect .sorts to work in FooController.

      base.sorts= [{:order => :alphabetical, :sort_direction => :asc}]
    end
    def sort_params
      params.slice(:order, :sort_direction).reverse_merge(default_sort_params)
    end
    def default_sort_params
      self.class.sorts.first
    end
   end
 end
于 2010-03-03T23:04:59.800 回答