2009-07-02 10 views
1

基本的には、コントローラのメソッドの重大性を定義するために単純なRails拡張を実装して、それらの使用を適切に制限できるようにしたいと思います。例えば、私は抽象スーパークラスになるようにデフォルト安らかなアクションを定義したい:クラスのデフォルトを設定し、サブクラスのオーバーライドを許可するRuby on Railsパターン

view_methods :index, :show 
edit_methods :new, :create, :edit, :update 
destroy_methods :destroy 

を私はその後、ダウン非抽象コントローラコールでたい:

edit_methods :sort 

は、sortメソッドに追加しますその特定のコントローラ上では編集レベルの方法である。

これで、before_filterを使用して現在実行中のアクションのレベルを確認し、自分のロジックで現在のユーザーが実行できないと判断した場合は中止できます。

問題は、この種の構造を設定する方法がわかりません。私はこれまでのところ、このような何かを試してみた:

class ApplicationController 

    @@view_methods = Array.new 
    @@edit_methods = Array.new 
    @@destroy_methods = Array.new 

    def self.view_methods(*view_methods) 
    class_variable_set(:@@view_methods, class_variable_get(:@@view_methods) << view_methods.to_a) 
    end 

    def self.edit_methods(*edit_methods) 
    class_variable_set(:@@edit_methods, self.class_variable_get(:@@edit_methods) << edit_methods.to_a) 
    end 

    def self.destroy_methods(*destroy_methods) 
    @@destroy_methods << destroy_methods.to_a 
    end 

    def self.testing 
    return @@edit_methods 
    end 


    view_methods :index, :show 
    edit_methods :new, :create, :edit, :update 
    destroy_methods :destroy 

end 

上記の3つの方法がちょうど私が試したものをお見せするために、意図的に異なっています。 3つ目は動作しますが、どのコントローラをテストしても同じ結果が返されます。おそらくクラス変数がアプリケーションコントローラに格納されているので、グローバルに変更されるからです。

ご協力いただければ幸いです。

答えて

3

問題は、クラス変数が継承されていますが、同じインスタンスArrayを指していることです。更新すると、Arrayを継承したすべてのクラスでも更新されます。

ActiveSupport継承クラスはを属性を定義するために、いくつかの方法でClassクラスを拡張することにより、この問題にsolutionを提供しています。それらはRailsの内部でどこでも使用されています。例:

class ApplicationController 
    class_inheritable_array :view_method_list 
    self.view_method_list = [] 

    def self.view_methods(*view_methods) 
    self.view_method_list = view_methods # view_methods are added 
    end 

    view_methods :index, :show 
end 

今、あなたはApplicationControllerにデフォルト値を設定することができますし、後でそれを上書きします。

class MyController < ApplicationController 
    view_method :my_method 
end 

ApplicationController.view_method_list #=> [:index, :show] 
MyController.view_method_list #=> [:index, :show, :my_method] 

あなたも、コントローラ(例えばMyController.new.view_method_list)にインスタンス方法としてview_method_listを使用することができます。

あなたの例では、あなたがリストからメソッドを削除する方法を定義していませんでしたが、アイデアは、以下の(あなたがそれを必要とする場合)のような何かを行うことです。

# given the code above... 
class MyController 
    self.view_method_list.delete :show 
end 
MyController.view_method_list #=> [:index, :my_method] 
+0

うわー!それはまさに私が探していたものです。その情報をありがとうございます。これが他の人にも役立つことを願っています。それはあなたがそれに答えてうれしいので、それを検索するのは難しいです:) –

0

私はにそれを回しましたこのようなプラグイン:

module ThreatLevel 

    def self.included(base) 
    base.send :extend, ClassMethods 
    end 

    module ClassMethods 
    def roger_that! 
     class_inheritable_array :view_method_list, :edit_method_list, :destroy_method_list 

     self.view_method_list = Array.new 
     self.edit_method_list = Array.new 
     self.destroy_method_list = Array.new 

     def self.view_methods(*view_methods) 
     self.view_method_list = view_methods 
     end 

     def self.edit_methods(*edit_methods) 
     self.edit_method_list = edit_methods 
     end 

     def self.destroy_methods(*destroy_methods) 
     self.destroy_method_list = destroy_methods 
     end 

     view_methods :index, :show 
     edit_methods :new, :create, :edit, :update 
     destroy_methods :destroy 
    end 
    end 
end 

ActionController::Base.send :include, ThreatLevel 

roger_that! super_controller上でそれを有効にしたいところがトリックです。

関連する問題