Patrón Ruby on Rails para establecer valores predeterminados de clase y permitir una anulación de subclases

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

Pregunta

Básicamente, quiero implementar una extensión Rails simple para definir la seriedad de los métodos en mi controlador para poder restringir su uso de manera adecuada.Por ejemplo, definiría las acciones de descanso predeterminadas así en una superclase abstracta:

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

Luego hice una llamada de controlador no abstracta:

edit_methods :sort

para agregar el método de clasificación en ese controlador en particular como un método de nivel de edición.

Luego podría usar before_filter para verificar el nivel de la acción que se está realizando actualmente y cancelarla si mi lógica determina que el usuario actual no puede hacerlo.

El problema es que tengo problemas para saber cómo configurar este tipo de estructura.He probado algo como esto hasta ahora:

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

Los tres métodos anteriores son diferentes a propósito, sólo para mostrarte lo que he probado.El tercero funciona, pero arroja los mismos resultados sin importar qué controlador pruebe.Probablemente porque las variables de clase se almacenan en el controlador de la aplicación y se cambian globalmente.

Cualquier ayuda sería muy apreciada.

¿Fue útil?

Solución

El problema es que las variables de tu clase se heredan, pero apuntan a la misma instancia de Array.Si actualiza uno, también se actualizará en todas las clases que heredaron el Array.

ActiveSupport ofrece una solución a este problema ampliando el Class clase con varios métodos para definir atributos de clase heredables.Se utilizan en todas partes internamente en Rails.Un ejemplo:

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

Ahora puedes establecer valores predeterminados en ApplicationController y anularlos más tarde.

class MyController < ApplicationController
  view_method :my_method
end

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

Incluso puedes usar el view_method_list como un instancia método en los controladores (p. ej. MyController.new.view_method_list).

En tu ejemplo no definiste una forma de eliminar métodos de las listas, pero la idea es hacer algo como lo siguiente (en caso de que lo necesites):

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

Otros consejos

Me di vuelta en un plugin de este modo:

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

Llamando roger_that! en el super_controller en la que desea que entre en vigor hace el truco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top