Захищені та приватні методи в Rails


81

Видимість методів у Ruby (загальнодоступні, захищені та приватні методи) добре пояснюється в таких місцях, як ця публікація в блозі . Але в Ruby on Rails це здається дещо іншим, ніж це було б у звичайному додатку Ruby, через те, як налаштовано фреймворк. Отже, у моделях Rails, контролерах, помічниках, тестах тощо, коли / чи не доречно використовувати захищені чи приватні методи?

Редагувати : Дякую за відповіді. Я розумію концепцію захищеного та приватного в Ruby, але я більше шукаю пояснення типового способу використання цих типів видимості в контексті різних частин програми Rails (моделі, контролери, помічники, тести) . Наприклад, методи публічного контролера - це методи дії, захищені методи в контролері додатків використовуються для «допоміжних методів», до яких потрібно отримати доступ кількома контролерами тощо.

Відповіді:


106

Для моделей ідея полягає в тому, що загальнодоступні методи є загальнодоступним інтерфейсом класу. Відкриті методи призначені для використання іншими об'єктами, тоді як захищені / приватні методи повинні бути приховані зовні.

Це така ж практика, як і в інших об’єктно-орієнтованих мовах.

Щодо контролерів та тестів, просто робіть як завгодно. І контролер, і тестові класи створюються лише за допомогою екземпляра і викликаються фреймворком ( так, я знаю, що теоретично ви можете отримати контролер з подання, але якщо ви це зробите, все одно щось дивно ). Оскільки ніхто ніколи не буде створювати ці речі безпосередньо, немає від чого "захиститися".

Додаток / виправлення: Для контролерів ви повинні позначити методи "допоміжних" як захищені приватні, і лише самі дії повинні бути загальнодоступними. Структура ніколи не спрямовує будь-які вхідні виклики HTTP до дій / методів, які не є загальнодоступними, тому ваші допоміжні методи повинні бути захищені таким чином.

Для помічників не матиме значення, якщо метод захищений або приватний, оскільки їх завжди називають "безпосередньо".

Ви можете позначити речі захищеними у всіх цих випадках, якщо це, звичайно, полегшує вам розуміння.


" Для контролерів ви повинні позначити" допоміжні "методи як захищені, і лише самі дії повинні бути загальнодоступними. " Чи радите ви не мати приватних методів у контролерах? Або я не повинен читати це буквально?
Денніс

2
В даний час я використовую лише приватне. захищені та приватні в більшості місць використовуються як взаємозамінні; але захищений приносить дивну поведінку, яка мені ніколи не потрібна в реальному світі.
averell

2
Я, як правило, використовую лише приватне. Це також відповідає певним рекомендаціям, наприклад, Thoughtbot "Використовуйте приватний, а не захищений при визначенні методів контролера".
Денніс

68

Ви використовуєте приватний метод, якщо не хочете нікого іншого, крімself використання методу. Ви використовуєте захищений метод, якщо хочете, щоб щось self and is_a?(self)викликало лише s.

Хорошим використанням захищеного може бути, якщо у вас був "віртуальний" метод ініціалізації.

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 матиме різні значення. а похідні екземпляри не матимуть @baz

Оновлення: Оскільки я написав це, деякі речі змінилися в Ruby 2.0+ Аарон Паттерсон має чудовий запис http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html


10
Любіть, як ви сказали self and is_a?(self). Я завжди пояснював, що захищені методи доступні в дитячих класах.
Тейт Джонсон,

16
Увага тут! Це важлива відмінність від інших мов: приватні методи також доступні в дочірніх класах. Єдина відмінність у приватному та захищеному полягає в тому, що ви можете викликати захищені методи за допомогою "self.set_defaults", тоді як приватні методи можна викликати лише як "set_defaults".
averell

Прекрасна відповідь, але навіть не містить слова Rails, що є СУТНІМ питанням
Bryan Ash

5
Зверніть увагу на час редагування його запитання. Надалі я
визначу

Як сказав Аверелл, це пояснення не стосується рубіну. Де приватні методи також видно в дочірніх класах.
Мігель

10

Різниця між захищеним та приватним є незначною. Якщо метод захищений, його може викликати будь-який екземпляр визначального класу або його підкласів. Якщо метод є приватним, його можна викликати лише в контексті викликуваного об'єкта --- ніколи неможливо отримати прямий доступ до приватних методів іншого екземпляра об'єкта, навіть якщо об'єкт має той самий клас, що і викликає. Для захищених методів вони доступні з об’єктів одного класу (або дітей).

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


2
Дякую за посилання. Але мені цікаво більше про те, як вони працюють конкретно в Ruby on Rails (методи публічного контролера розглядаються як методи дії, захищені методи в контролері додатків можуть використовуватися іншими контролерами тощо)
jrdioko

3
В останньому випадку "захищені методи в контролері додатків можуть використовувати інші контролери", це тому, що інші контролери (як правило) успадковують від ApplicationController, тому вони насправді самі володіють усіма цими методами. Вони не отримують до них доступ з application_controller: це ніколи не створюється. Він чисто використовується як батько для успадкування.
Макс Вільямс,

3

Ви, мабуть, добре уявляєте семантику видимості класів (загальнодоступна / захищена / приватна), яка застосовується до методів. Все, що я можу запропонувати, - це короткий опис того, як я впроваджую це у своїх програмах Rails.

Я реалізую захищені методи в базовому контролері додатків, щоб їх міг викликати будь-який контролер через фільтри (наприклад, before_filter: method_foo). Подібним чином я визначаю захищені методи для моделей, які я хочу використовувати в усіх з них у базовій моделі, від якої всі вони успадковують.


2

Хоча дії повинні бути загальнодоступними методами контролера, не всі загальнодоступні методи обов'язково є діями. Ви можете використовувати, hide_actionякщо ви використовуєте загальнодоступний маршрут, наприклад, /:controller/:action/:idабо якщо він вимкнений (за замовчуванням у Rails 3), тоді будуть викликані лише методи з явними маршрутами.

Це може бути корисно, якщо ви передаєте екземпляр контролера до іншої бібліотеки, як механізм шаблону Liquid, оскільки ви можете надати загальнодоступний інтерфейс, а не використовувати send у ваших фільтрах та тегах Liquid.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.