Geschützte und private Methoden in Rails

81

Die Sichtbarkeit von Methoden in Ruby (öffentliche, geschützte und private Methoden) wurde an Stellen wie diesem Blog-Beitrag ausführlich erläutert . In Ruby on Rails scheint es jedoch etwas anders zu sein als in einer normalen Ruby-Anwendung, da das Framework so eingerichtet ist. Wann ist / ist es in Rails-Modellen, Controllern, Helfern, Tests usw. angemessen, geschützte oder private Methoden zu verwenden?

Edit : Danke für die bisherigen Antworten. Ich verstehe das Konzept von geschützt und privat in Ruby, suche aber eher nach einer Erklärung für die typische Art und Weise, wie diese Sichtbarkeitstypen im Kontext der verschiedenen Teile einer Rails-App verwendet werden (Modelle, Controller, Helfer, Tests). . Beispielsweise sind öffentliche Controller-Methoden Aktionsmethoden, geschützte Methoden im Anwendungs-Controller werden für "Hilfsmethoden" verwendet, auf die mehrere Controller zugreifen müssen usw.

jrdioko
quelle

Antworten:

106

Bei Modellen besteht die Idee darin, dass die öffentlichen Methoden die öffentliche Schnittstelle der Klasse sind. Öffentliche Methoden sollen von anderen Objekten verwendet werden, während geschützte / private Methoden von außen verborgen werden sollen.

Dies ist die gleiche Praxis wie in anderen objektorientierten Sprachen.

Tun Sie für Controller und Tests einfach, was Sie möchten. Sowohl Controller- als auch Testklassen werden nur vom Framework instanziiert und aufgerufen ( ja, ich weiß, dass Sie den Controller theoretisch aus der Ansicht abrufen können, aber wenn Sie dies tun, ist sowieso etwas seltsam ). Da niemand diese Dinge jemals direkt erschaffen wird, gibt es nichts, vor dem man sich "schützen" kann.

Nachtrag / Korrektur: Für Controller sollten Sie die "Hilfs" -Methoden als geschützt privat markieren und nur die Aktionen selbst sollten öffentlich sein. Das Framework leitet keine eingehenden HTTP-Aufrufe an Aktionen / Methoden weiter, die nicht öffentlich sind. Daher sollten Ihre Hilfsmethoden auf diese Weise geschützt werden.

Für Helfer spielt es keine Rolle, ob eine Methode geschützt oder privat ist, da sie immer "direkt" genannt werden.

In all diesen Fällen können Sie Dinge markieren, die geschützt sind, wenn dies natürlich das Verständnis erleichtert.

Averell
quelle
" Für Controller sollten Sie die" Hilfs "-Methoden als geschützt markieren und nur die Aktionen selbst sollten öffentlich sein. " Empfehlen Sie, keine privaten Methoden in Controllern zu haben? Oder sollte ich das nicht wörtlich lesen?
Dennis
2
Heutzutage benutze ich nur privat. geschützt und privat werden an den meisten Orten synonym verwendet; aber geschützt bringt ein seltsames Verhalten mit sich, das ich in der realen Welt nie gebraucht habe.
Averell
2
Ich neige dazu, auch nur privat zu benutzen. Dies folgt auch bestimmten Richtlinien, wie beispielsweise Thoughtbots "Beim Definieren von Controller-Methoden privat statt geschützt verwenden".
Dennis
66

Sie verwenden eine private Methode , wenn Sie wollen , niemand anderes alsself eine Methode zu verwenden. Sie verwenden eine geschützte Methode, wenn Sie etwas möchten, das nur self and is_a?(self)s aufrufen kann.

Eine gute Verwendung von protected könnte sein, wenn Sie eine "virtuelle" Initialisierungsmethode hatten.

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 hat unterschiedliche Werte. und die abgeleiteten Instanzen haben kein @baz

Update: Seit ich dies geschrieben habe, haben sich einige Dinge in Ruby 2.0+ geändert. Aaron Patterson hat eine hervorragende Beschreibung: http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html

EnabrenTane
quelle
9
Liebe, wie du gesagt hast self and is_a?(self). Ich habe geschützte Methoden immer als in Kinderklassen verfügbar erklärt.
Tate Johnson
16
Achtung hier! Dies ist ein wichtiger Unterschied zu anderen Sprachen: Private Methoden sind auch in untergeordneten Klassen verfügbar. Der einzige Unterschied zwischen privat und geschützt besteht darin, dass Sie geschützte Methoden mit "self.set_defaults" aufrufen können, während private Methoden nur als "set_defaults" aufgerufen werden können.
Averell
Eine gute Antwort, enthält aber nicht einmal das Wort Rails, was DER Punkt der Frage ist
Bryan Ash
5
Beachten Sie den Bearbeitungsstempel seiner Frage. In Zukunft werde ich eine private Methode definieren, um meine Antworten zu aktualisieren, wenn sie ihre Fragen ändern :)
EnabrenTane
Wie Averell sagte, gilt diese Erklärung nicht für Rubin. Wo private Methoden auch in untergeordneten Klassen sichtbar sind.
Miguel
10

Der Unterschied zwischen geschützt und privat ist subtil. Wenn eine Methode geschützt ist, kann sie von einer beliebigen Instanz der definierenden Klasse oder ihrer Unterklassen aufgerufen werden. Wenn eine Methode privat ist, kann sie nur im Kontext des aufrufenden Objekts aufgerufen werden. Es ist niemals möglich, direkt auf die privaten Methoden einer anderen Objektinstanz zuzugreifen, selbst wenn das Objekt derselben Klasse wie der Aufrufer angehört. Auf geschützte Methoden kann von Objekten derselben Klasse (oder von untergeordneten Objekten) aus zugegriffen werden.

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

Nunopolonia
quelle
2
Danke für den Link. Aber ich frage mich mehr darüber, wie diese speziell in Ruby on Rails funktionieren (öffentliche Controller-Methoden werden als Aktionsmethoden behandelt, geschützte Methoden im Anwendungs-Controller können von anderen Controllern verwendet werden usw.)
jrdioko
3
Im letzten Fall "können geschützte Methoden im Anwendungscontroller von anderen Controllern verwendet werden" liegt dies daran, dass die anderen Controller (im Allgemeinen) von ApplicationController erben, sodass sie tatsächlich alle diese Methoden selbst besitzen. Sie greifen nicht über application_controller auf sie zu: Dies wird nie instanziiert. Es wird nur als übergeordnetes Element zum Erben verwendet.
Max Williams
3

Sie scheinen eine gute Vorstellung von der Semantik der Sichtbarkeit von Klassen (öffentlich / geschützt / privat) zu haben, die auf Methoden angewendet wird. Ich kann nur einen kurzen Überblick darüber geben, wie ich es in meinen Rails-Apps implementiere.

Ich implementiere geschützte Methoden im Basisanwendungs-Controller, damit sie von jedem Controller über Filter aufgerufen werden können (z. B. before_filter: method_foo). Auf ähnliche Weise definiere ich geschützte Methoden für Modelle, die ich in allen in einem Basismodell verwenden möchte, von dem sie alle erben.

Sasha
quelle
2

Obwohl Aktionen öffentliche Methoden eines Controllers sein müssen, sind nicht alle öffentlichen Methoden notwendigerweise Aktionen. Sie können nur Methoden mit expliziten Routen aufrufen, hide_actionwenn Sie eine Sammelroute wie verwenden /:controller/:action/:idoder wenn diese deaktiviert ist (Standardeinstellung in Rails 3).

Dies kann nützlich sein, wenn Sie die Controller-Instanz an eine andere Bibliothek wie die Liquid Template Engine übergeben, da Sie eine öffentliche Schnittstelle bereitstellen können, anstatt send in Ihren Liquid-Filtern und -Tags verwenden zu müssen.

Pixeltrix
quelle