Métodos protegidos y privados en Rails


La visibilidad del método en Ruby (métodos públicos, protegidos y privados) ha sido bien explicada en lugares como esta entrada de blog. Pero en Ruby on Rails parece ligeramente diferente de lo que sería en una aplicación Ruby normal debido a la forma en que se configura el framework. Así, en modelos de Rails, controladores, ayudantes, pruebas, etc., ¿cuándo es / no es apropiado usar métodos protegidos o privados?

Edit : Gracias por las respuestas hasta ahora. Entiendo el concepto de protegido y privado en Ruby, pero estoy buscando más una explicación de la forma típica en que se utilizan esos tipos de visibilidad dentro del contexto de las diversas piezas de una aplicación Rails (modelos, controladores, ayudantes, pruebas). Por ejemplo, los métodos de controlador público son métodos de acción, los métodos protegidos en el controlador de aplicación se utilizan para" métodos auxiliares " a los que deben acceder varios controladores, etc.

Author: jrdioko, 2010-12-21

5 answers

Para los modelos, la idea es que los métodos públicos son la interfaz pública de la clase. Los métodos públicos están destinados a ser utilizados por otros objetos, mientras que los métodos protegidos/privados deben estar ocultos desde el exterior.

Esta es la misma práctica que en otros lenguajes orientados a objetos.

Para los controladores y las pruebas, haga lo que quiera. Tanto el controlador como las clases de prueba solo son instanciadas y llamadas por el framework ( sí, sé que puedes teóricamente obtenga el controlador desde la vista, pero si lo hace, algo es extraño de todos modos ). Ya que nadie creará esas cosas directamente, no hay nada contra lo que" proteger".

Addendum / Correction: Para los controladores, debe marcar los métodos "helper" como protegidos privados, y solo las acciones en sí deben ser públicas. El framework nunca enrutará ninguna llamada HTTP entrante a acciones / métodos que no sean públicos, por lo que sus métodos helper deben estar protegidos de esa manera.

Para los ayudantes no hará ninguna diferencia si un método es protegido o privado, ya que siempre se les llama "directamente".

Puedes marcar cosas protegidas en todos esos casos si te hace las cosas más fáciles de entender, por supuesto.

 98
Author: averell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-01 15:56:09

Se utiliza un método privado si se quiere nadie más que self para usar un método. Se utiliza un método protegido si se quiere algo que solo self and is_a?(self) s puede llamar.

Un buen uso de protected podría ser si tuviera un método de inicialización "virtual".

class Base
    def initialize()
        set_defaults()
        #other stuff
    end

    protected
    def set_defaults()
        # defaults for this type
        @foo = 7
        calculate_and_set_baz()
    end

    private
    def calculate_and_set_baz()
        @baz = "Something that only base classes have like a file handle or resource"
    end
end

class Derived < Base
    protected
    def set_defaults()
        @foo = 13
    end
end

@foo tendrá diferentes valores. y las instancias derivadas no tendrán @baz

Actualizar: Desde que escribí esto, algunas cosas han cambiado en Ruby 2.0+ Aaron Patterson tiene una excelente escritura http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html

 62
Author: EnabrenTane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-06 23:30:29

La diferencia entre protegido y privado es sutil. Si un método es protegido, puede ser llamado por cualquier instancia de la clase definidora o su subclases. Si un método es privado, puede ser llamado solo dentro del contexto del objeto que llama - - - nunca es posibilidad de acceder a otro objeto métodos privados de la instancia directamente, incluso si el objeto es del mismo clase como el que llama. Para protegido métodos, son accesibles desde objetos de la misma clase (o niño).

Http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Declaring_Visibility

 9
Author: nunopolonia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-20 23:54:15

Parece tener una buena idea de la semántica de la visibilidad de clase (pública/protegida/privada) aplicada a los métodos. Todo lo que puedo ofrecer es un resumen rápido de la forma en que lo implemento en mis aplicaciones Rails.

Implemento métodos protegidos en el controlador de aplicación base para que puedan ser llamados por cualquier controlador a través de filtros (por ejemplo, before_filter :method_foo). De manera similar, defino métodos protegidos para los modelos que quiero usar en todos ellos en un modelo base del que todos heredan.

 3
Author: Sasha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-04 07:09:46

Aunque las acciones deben ser métodos públicos de un controlador, no todos los métodos públicos son necesariamente acciones. Usted puede utilizar hide_action si está utilizando una ruta catch-all como /:controller/:action/:id o si está deshabilitada (la predeterminada en Rails 3), solo se llamarán a los métodos con rutas explícitas.

Esto puede ser útil si está pasando la instancia del controlador a alguna otra biblioteca como el motor de plantillas Liquid, ya que puede proporcionar una interfaz pública en lugar de tener que usar send en su Liquid filtros y etiquetas.

 2
Author: pixeltrix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-29 21:16:39