Защищенные и частные методы в Rails

81

Видимость методов в Ruby (общедоступные, защищенные и частные методы) хорошо объяснена в таких местах, как это сообщение в блоге . Но в Ruby on Rails это выглядит немного иначе, чем в обычном приложении Ruby, из-за способа настройки фреймворка. Итак, в моделях, контроллерах, помощниках, тестах и ​​т.д. Rails, когда уместно / не уместно использовать защищенные или частные методы?

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

Jrdioko
источник

Ответы:

106

Для моделей идея состоит в том, что общедоступные методы являются общедоступным интерфейсом класса. Открытые методы предназначены для использования другими объектами, в то время как защищенные / частные методы должны быть скрыты извне.

Это та же практика, что и в других объектно-ориентированных языках.

Что касается контроллеров и тестов, делайте все, что хотите. Контроллер и тестовые классы создаются и вызываются только фреймворком ( да, я знаю, что теоретически вы можете получить контроллер из представления, но если вы это сделаете, все равно что-то будет странно ). Поскольку никто никогда не будет создавать эти вещи напрямую, «защищаться» не от чего.

Дополнение / Исправление: Для контроллеров вы должны пометить «вспомогательные» методы как защищенные частные, и только сами действия должны быть общедоступными. Платформа никогда не будет направлять входящие HTTP-вызовы к действиям / методам, которые не являются общедоступными, поэтому ваши вспомогательные методы должны быть защищены таким образом.

Для помощников не имеет значения, является ли метод защищенным или закрытым, поскольку они всегда вызываются «напрямую».

Вы можете пометить вещи как защищенные во всех этих случаях, если, конечно, вам будет легче понять.

Аверелл
источник
« Для контроллеров вы должны пометить« вспомогательные »методы как защищенные, и только сами действия должны быть общедоступными. « Вы советуете не иметь никаких частных методов в контроллерах? Или мне не следует читать это буквально?
Деннис
2
В настоящее время я использую только приват. защищенный и частный используются как синонимы в большинстве мест; но protected приводит к странному поведению, которое мне никогда не нужно в реальном мире.
Averell 01
2
Я тоже использую только частные. Это также соответствует определенным рекомендациям, таким как Thoughtbot «Используйте частные вместо защищенных при определении методов контроллера».
Деннис
68

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

Хорошее использование protected может быть, если у вас есть «виртуальный» метод инициализации.

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

EnabrenTane
источник
10
Люблю, как ты сказал self and is_a?(self). Я всегда объяснял, что защищенные методы доступны в дочерних классах.
Тейт Джонсон
16
Внимание здесь! Это важное отличие от других языков: частные методы также доступны в дочерних классах. Единственная разница между частными и защищенными методами заключается в том, что вы можете вызывать защищенные методы с помощью «self.set_defaults», в то время как частные методы могут вызываться только как «set_defaults».
Averell
Хороший ответ, но даже не содержит слова Rails, которое является сутью вопроса
Брайан Эш
5
Обратите внимание на метку времени редактирования его вопроса. В будущем я определю частный метод для обновления моих ответов, когда они меняют свои вопросы :)
EnabrenTane
Как сказал Аверелл, это объяснение не относится к рубину. Где частные методы также видны в дочерних классах.
Мигель
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.

Pixeltrix
источник