Metody chronione i prywatne w Railsach


81

Widoczność metod w Rubim (metody publiczne, chronione i prywatne) została dobrze wyjaśniona w miejscach takich jak ten post na blogu . Jednak w Ruby on Rails wygląda to nieco inaczej niż w zwykłej aplikacji Ruby ze względu na sposób skonfigurowania frameworka. Zatem w modelach Railsowych, kontrolerach, pomocnikach, testach itp., Kiedy jest / nie jest właściwe stosowanie metod chronionych lub prywatnych?

Edycja : Dzięki za dotychczasowe odpowiedzi. Rozumiem pojęcie chronionego i prywatnego w Rubim, ale szukam bardziej wyjaśnienia typowego sposobu, w jaki te typy widoczności są używane w kontekście różnych elementów aplikacji Railsowej (modele, kontrolery, pomocniki, testy) . Na przykład metody kontrolera publicznego są metodami akcji, metody chronione w kontrolerze aplikacji są używane jako „metody pomocnicze”, do których dostęp musi mieć wiele kontrolerów itp.

Odpowiedzi:


106

W przypadku modeli chodzi o to, że metody publiczne są publicznym interfejsem klasy. Metody publiczne są przeznaczone do użycia przez inne obiekty, podczas gdy metody chronione / prywatne mają być ukryte z zewnątrz.

Jest to ta sama praktyka, co w innych językach zorientowanych obiektowo.

W przypadku kontrolerów i testów rób, co chcesz. Zarówno klasy kontrolera, jak i testowe są tylko tworzone i wywoływane przez framework ( tak, wiem, że teoretycznie można uzyskać kontroler z widoku, ale jeśli to zrobisz, i tak coś jest dziwne ). Ponieważ nikt nigdy nie stworzy tych rzeczy bezpośrednio, nie ma przed czym „ochrony”.

Dodatek / korekta: W przypadku kontrolerów należy oznaczyć metody „pomocnika” jako chronione prywatne i tylko same akcje powinny być publiczne. Framework nigdy nie przekieruje żadnych przychodzących wywołań HTTP do akcji / metod, które nie są publiczne, więc Twoje metody pomocnicze powinny być chronione w ten sposób.

Dla pomocników nie będzie miało znaczenia, czy metoda jest chroniona czy prywatna, ponieważ są zawsze wywoływani „bezpośrednio”.

We wszystkich tych przypadkach możesz oznaczyć elementy chronione, jeśli oczywiście ułatwi to zrozumienie.


W przypadku kontrolerów należy oznaczyć metody„ pomocnika ”jako chronione, a tylko same akcje powinny być publiczne. ” Czy radzisz nie mieć żadnych prywatnych metod w kontrolerach? A może nie powinienem czytać tego dosłownie?
Dennis

2
Obecnie używam tylko prywatnych. chronione i prywatne są używane zamiennie w większości miejsc; ale chroniony przynosi dziwne zachowanie, którego nigdy nie potrzebowałem w prawdziwym świecie.
averell

2
Zwykle używam tylko prywatnego. Jest to również zgodne z pewnymi wytycznymi, takimi jak „Używaj prywatnego zamiast chronionego podczas definiowania metod kontrolera”.
Dennis,

68

Używasz metody prywatnej, jeśli nie chcesz nikogo innego, jak tylkoself użyć metody. Używasz metody chronionej, jeśli chcesz, aby coś self and is_a?(self)mogło wywołać tylko s.

Dobrym zastosowaniem chronionego może być „wirtualna” metoda inicjalizacji.

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 będzie miało różne wartości. a instancje pochodne nie będą miały @baz

Aktualizacja: Odkąd to napisałem, niektóre rzeczy uległy zmianie w Ruby 2.0+ Aaron Patterson świetnie napisał http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html


10
Uwielbiam to, jak powiedziałeś self and is_a?(self). Zawsze wyjaśniałem metody chronione jako dostępne w klasach dla dzieci.
Tate Johnson,

16
Uwaga! Jest to ważna różnica w porównaniu z innymi językami: w klasach dla dzieci dostępne są również metody prywatne . Jedyna różnica między prywatnymi i chronionymi polega na tym, że można wywoływać metody chronione za pomocą „self.set_defaults”, podczas gdy metody prywatne można wywoływać tylko jako „set_defaults”.
averell,

Dobra odpowiedź, ale nie zawiera nawet słowa Rails, które jest głównym celem pytania
Bryan Ash,

5
Zwróć uwagę na znacznik czasu edycji jego pytania. W przyszłości zdefiniuję prywatną metodę aktualizowania moich odpowiedzi, gdy zmieniają swoje pytania :)
EnabrenTane

Jak powiedział Averell, wyjaśnienie to nie dotyczy rubinu. Gdzie metody prywatne są również widoczne w klasach potomnych.
Miguel

10

Różnica między chronionym a prywatnym jest subtelna. Jeśli metoda jest chroniona, może zostać wywołana przez dowolną instancję klasy definiującej lub jej podklas. Jeśli metoda jest prywatna, może być wywoływana tylko w kontekście obiektu wywołującego - nigdy nie jest możliwy bezpośredni dostęp do metod prywatnych instancji innego obiektu, nawet jeśli obiekt jest tej samej klasy co obiekt wywołujący. W przypadku metod chronionych są one dostępne z obiektów tej samej klasy (lub elementów podrzędnych).

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


2
Dzięki za link. Ale zastanawiam się bardziej, jak działają one konkretnie w Ruby on Rails (metody kontrolera publicznego są traktowane jako metody akcji, metody chronione w kontrolerze aplikacji mogą być używane przez inne kontrolery itp.)
jrdioko

3
W ostatnim przypadku „metody chronione w kontrolerze aplikacji mogą być używane przez inne kontrolery”, ponieważ inne kontrolery (ogólnie) dziedziczą po ApplicationController, więc w rzeczywistości są właścicielami wszystkich tych metod. Nie uzyskują do nich dostępu z application_controller: to nigdy nie zostanie utworzone. Jest używany wyłącznie jako rodzic do dziedziczenia.
Max Williams,

3

Wygląda na to, że dobrze rozumiesz semantykę widoczności klas (publiczna / chroniona / prywatna) w zastosowaniu do metod. Wszystko, co mogę zaoferować, to szybki zarys sposobu, w jaki wdrażam go w moich aplikacjach Railsowych.

Implementuję metody chronione w podstawowym kontrolerze aplikacji, dzięki czemu mogą być wywoływane przez dowolny kontroler poprzez filtry (np. Before_filter: method_foo). W podobny sposób definiuję chronione metody dla modeli, których chcę używać we wszystkich w modelu podstawowym, z którego wszystkie dziedziczą.


2

Chociaż akcje muszą być publicznymi metodami kontrolera, nie wszystkie metody publiczne muszą być akcjami. Możesz użyć, hide_actionjeśli używasz trasy typu catch-all, takiej jak /:controller/:action/:idlub jeśli jest wyłączona (domyślnie w Railsach 3), wtedy wywołane zostaną tylko metody z jawnymi trasami.

Może to być przydatne, jeśli przekazujesz instancję kontrolera do innej biblioteki, takiej jak silnik szablonów Liquid, ponieważ możesz zapewnić publiczny interfejs, zamiast używać wysyłania w swoich filtrach i tagach Liquid.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.