Ruby on Rails motif pour le réglage par défaut de la classe et en permettant un remplacement sur les sous-classes

StackOverflow https://stackoverflow.com/questions/1072767

Question

En fait, je veux mettre en œuvre une simple extension Rails pour définir la gravité des méthodes dans mon contrôleur afin que je puisse restreindre l'utilisation d'entre eux de façon appropriée. Par exemple, je voudrais définir les actions reposant par défaut comme si dans un résumé superclasse:

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

Je puis dans un appel de commande non abstraite:

edit_methods :sort

pour ajouter dans la méthode de tri sur ce contrôleur particulier comme étant une méthode de niveau d'édition.

Je pourrais alors utiliser un before_filter pour vérifier le niveau de l'action actuellement en cours d'exécution, et l'annuler si ma logique détermine que l'utilisateur actuel ne peut pas le faire.

Le problème est, je vais avoir du mal à travailler sur la façon de mettre en place ce genre de structure. J'ai essayé quelque chose comme ça jusqu'à présent:

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

Les trois méthodes ci-dessus sont différentes sur le but, juste pour vous montrer ce que je l'ai essayé. La troisième marche, mais renvoie les mêmes résultats, peu importe ce que je commande test. Probablement parce que les variables de classe sont stockées dans le contrôleur d'application sont donc changé dans le monde.

Toute aide serait grandement appréciée.

Était-ce utile?

La solution

Le problème est que vos variables de classe sont héritées, mais pointent vers la même instance de Array. Si vous mettez à jour un, il sera également mis à jour sur toutes les classes qui ont hérité du ActiveSupport.

Class solution à ce problème en étendant la classe avec plusieurs méthodes ApplicationController pour définir attributs de classe héritable . Ils sont utilisés partout en interne dans Rails. Un exemple:

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

Maintenant, vous pouvez définir des valeurs par défaut dans les remplacer et view_method_list plus tard.

class MyController < ApplicationController
  view_method :my_method
end

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

On peut même utiliser la MyController.new.view_method_list comme méthode instance sur les contrôleurs (par exemple, <=>).

Dans votre exemple, vous n'avez pas défini un moyen de supprimer des méthodes des listes, mais l'idée est de faire quelque chose comme ce qui suit (en cas de besoin):

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

Autres conseils

Je me suis tourné dans un plugin comme ceci:

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

Appel roger_that! sur le super_controller où vous voulez qu'elle prenne effet le tour est joué.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top