2010-03-03 40 views
2

我想有一種單獨的列表,在單獨的模塊中初始化,然後可以包含在控制器中並在控制器級別修改,並在控制器訪問 - 實例級別。我認爲類變量可以在這裏工作,但是有些奇怪的事情正在發生,他們似乎沒有在我的結局類中被初始化。類變量和模塊包含,特別是在ActionController

更具體地說:

我有很多控制器都包括一些默認功能,一個模塊中。

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是一個糟糕的電話,但我想不出還有什麼我可能會使用。 (一個類實例變量?)

回答

0

我結束了使用一個類級別的實例變量,其中包括(),沒有autoincluded子模塊,注意到,@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 /排序.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 
2

類實例變量是肯定的路。很少你真的需要使用類變量。

在針對您的問題的特定答案中,請記住,模塊中定義的任何代碼僅執行一次當模塊加載時不包括模塊在內。這種區別可能並不明顯,特別是當人們認爲「包含」等同於「要求」時。

你需要的是這樣的:

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 =賦值函數方法,而不是set_var()
+0

請注意,我希望@sorts是類級別的,而不是實例級別。見下面我最終使用的答案。 我在我的問題中忽略了任何self.included()調用的原因 - 包含子模塊時,實例和類變量變得非常髒。因此,我將您的方法轉換爲DefaultFunctionality,從而有效地消除導致無法解決的頭痛的子模塊問題。 – 2010-03-03 23:11:28

+0

我同意聲明中的默認設置,我只是希望人們知道數據結構是什麼樣的。就像現在看來的那樣,我應該在宣言的一邊評論它。 – 2010-03-03 23:12:50

+0

在我的原始代碼中,我製作了單獨的SortOrder對象,因此有了make_sorts!在[order,dir,name]數組和SortOrder.new(order,dir,name)之間進行轉換的方法很有用。很顯然,情況並非如此。我已經修改了我的答案,以包含您的self.sorts風格;這個例子似乎是最好的。 – 2010-03-03 23:15:32

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