Métodos protegidos y privados en Rails

81

La visibilidad de métodos en Ruby (métodos públicos, protegidos y privados) se ha explicado bien en lugares como esta publicación 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 está configurado el marco. Entonces, en modelos, controladores, ayudantes, pruebas, etc. de Rails, ¿cuándo es / no es apropiado usar métodos protegidos o privados?

Editar : 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 usan esos tipos de visibilidad dentro del contexto de las diversas partes de una aplicación Rails (modelos, controladores, ayudantes, pruebas) . Por ejemplo, los métodos del controlador público son métodos de acción, los métodos protegidos en el controlador de la aplicación se utilizan para los "métodos auxiliares" a los que deben acceder varios controladores, etc.

jrdioko
fuente

Respuestas:

106

Para los modelos, la idea es que los métodos públicos sean 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 ocultarse desde el exterior.

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

Para controladores y pruebas, haz lo que quieras. Tanto el controlador como las clases de prueba solo son instanciadas y llamadas por el marco ( sí, sé que teóricamente puedes obtener el controlador desde la vista, pero si lo haces, algo es extraño de todos modos ). Dado que nadie creará esas cosas directamente, no hay nada contra lo que "protegerse".

Apéndice / Corrección: Para los controladores, debe marcar los métodos "auxiliares" como privados protegidos , y solo las acciones en sí mismas deben ser públicas. El marco nunca enrutará ninguna llamada HTTP entrante a acciones / métodos que no sean públicos, por lo que sus métodos auxiliares deben protegerse de esa manera.

Para los ayudantes no habrá diferencia si un método está protegido o es privado, ya que siempre se llaman "directamente".

Puede marcar cosas protegidas en todos esos casos si le facilita la comprensión, por supuesto.

averell
fuente
" Para los controladores, debe marcar los métodos" auxiliares "como protegidos, y solo las acciones en sí deben ser públicas. " ¿Está aconsejando no tener ningún método privado en los controladores? ¿O no debería leer eso literalmente?
Dennis
2
Hoy en día solo uso privado. protegido y privado se usan indistintamente en la mayoría de los lugares; pero protegido trae un comportamiento extraño que nunca necesité en el mundo real.
averell
2
Tiendo a usar solo privado también. Esto también sigue ciertas pautas, como "Usar privado en lugar de protegido al definir métodos de controlador" de Thoughtbot.
Dennis
66

Utiliza un método privado si no quiere que nadie másself utilice un método. Utiliza un método protegido si desea algo que solo los self and is_a?(self)s pueden 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á valores diferentes. y las instancias derivadas no tendrán @baz

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

EnabrenTane
fuente
9
Amo cómo dijiste self and is_a?(self). Siempre he explicado que los métodos protegidos están disponibles en las clases para niños.
Tate Johnson
16
¡Atención aquí! Esta es una diferencia importante con otros idiomas: los métodos privados también están disponibles en las clases para niños. La única diferencia entre privado y protegido es que puede llamar a métodos protegidos con "self.set_defaults", mientras que los métodos privados solo se pueden llamar como "set_defaults".
averell
Una buena respuesta, pero ni siquiera contiene la palabra Rails, que es EL punto de la pregunta
Bryan Ash
5
Observe la marca de tiempo de edición de su pregunta. En el futuro, definiré un método privado para actualizar mis respuestas a medida que cambien sus preguntas :)
EnabrenTane
Como dijo Averell, esta explicación no se aplica al rubí. Donde los métodos privados también son visibles en clases secundarias.
Miguel
10

La diferencia entre protegido y privado es sutil. Si un método está protegido, puede ser llamado por cualquier instancia de la clase definitoria o sus subclases. Si un método es privado, se puede llamar solo dentro del contexto del objeto que llama; nunca es posible acceder directamente a los métodos privados de otra instancia de objeto, incluso si el objeto es de la misma clase que el llamador. Para los métodos protegidos, se puede acceder a ellos desde objetos de la misma clase (o elementos secundarios).

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

nunopolonia
fuente
2
Gracias por el enlace. Pero me pregunto más sobre cómo funcionan específicamente en Ruby on Rails (los métodos de controlador público se tratan como métodos de acción, los métodos protegidos en el controlador de la aplicación pueden ser utilizados por otros controladores, etc.)
jrdioko
3
En el último caso, "los métodos protegidos en el controlador de la aplicación pueden ser utilizados por otros controladores", esto se debe a que los otros controladores (generalmente) heredan de ApplicationController, por lo que en realidad poseen todos esos métodos. No acceden a ellos desde application_controller: esto nunca se crea una instancia. Se usa puramente como padre para heredar.
Max Williams
3

Parece tener una buena idea de la semántica de la visibilidad de clases (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.

Sasha
fuente
2

Aunque las acciones deben ser métodos públicos de un controlador, no todos los métodos públicos son necesariamente acciones. Puede usar hide_actionsi está usando una ruta general /:controller/:action/:ido si está deshabilitada (el valor predeterminado en Rails 3), solo se llamarán 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 plantilla Liquid, ya que puede proporcionar una interfaz pública en lugar de tener que enviar sus filtros y etiquetas Liquid.

pixeltrix
fuente