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

確かに、クラス インスタンス変数は最適な方法です。クラス変数を実際に使用する必要があることはめったにありません。

問題に対する具体的な答えとして、モジュールで定義されたコードは、モジュールが含まれているときではなく、モジュールがロードされたときに1回だけ実行されることに注意してください。この区別は、特に「含める」を「必要とする」と同等であると見なす場合には、明らかではない可能性があります。

必要なものはこれです:

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 が呼び出され、呼び出しクラスのコンテキスト内にあります。

これを少し修正して、いくつかの特定のスタイル変更を含めました。

  • 宣言ではなく、メソッド内でデフォルトを宣言します。読めないほど長い行を作成したり、複雑なデータ構造を 1 行にまとめたりする必要がなくなります。
  • この場合、ジョブを実行するクラス インスタンス変数を使用します。
  • set_var() の代わりに Ruby スタイルの var= mutator メソッドを使用する
于 2010-03-03T20:13:59.293 に答える
0

@tadmanが応答したことに気付く前に、クラスレベルのインスタンス変数と、自動インクルードされたサブモジュールのないincluded()を使用することになりました。

最終的には次のようになりました。

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 に答える
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 に答える