Rails中受保护的私有方法


81

Ruby的方法可见性(公共方法,受保护方法和私有方法)已在本博客文章之类的地方得到了很好的解释。但是在Ruby on Rails中,由于框架的设置方式,它似乎与常规Ruby应用程序中的稍有不同。因此,在Rails模型,控制器,助手,测试等中,何时/不适合使用受保护的方法或私有方法?

编辑:谢谢你到目前为止的答案。我了解Ruby中保护和私有的概念,但我希望更多地解释在Rails应用的各个部分(模型,控制器,助手,测试)的上下文中使用这些可见性的典型方式。 。例如,公共控制器方法是操作方法,应用程序控制器中受保护的方法用于需要多个控制器访问的“帮助器方法”等。

Answers:


106

对于模型,其思想是公共方法是类的公共接口。公共方法旨在供其他对象使用,而受保护/私有方法则应从外部隐藏。

这与其他面向对象的语言相同。

对于控制器和测试,请随便做。控制器测试类都仅由框架实例化和调用(是的,我知道您理论上可以从视图中获取控制器,但是如果您这样做,反正有些奇怪)。由于没有人会直接创造这些东西,因此没有什么可以“防御”的。

附录/更正:对于控制器,应将“帮助器”方法标记为受保护的私有方法,并且只有动作本身才应该是公共的。该框架绝不会将任何传入的HTTP调用路由到非公开的操作/方法,因此,您的帮助方法应该受到这种保护。

对于助手来说,如果方法是受保护的或私有的,则不会有任何区别,因为它们始终被称为“直接”。

当然,您可以在所有这些情况下都将受保护的内容标记为受保护的内容。


对于控制器,您应该将“帮助器”方法标记为受保护,并且只有动作本身应该是公开的。 “是否建议控制器中不包含任何私有方法?还是我不应该从字面上看?
丹尼斯

2
如今,我只使用私有的。受保护的和私有的在大多数地方可以互换使用;但是受到保护会带来我在现实世界中从未需要的奇怪行为。
averell

2
我也倾向于只使用私有的。这也遵循某些准则,例如Thoughtbot的“定义控制器方法时使用私有而不是受保护的”。
丹尼斯2014年

66

如果你想使用的私有方法没有其他人,但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+中的某些事情发生了变化。Aaron Patterson撰写了出色的文章http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html


9
爱你怎么说self and is_a?(self)。我一直将受保护的方法解释为可在子类中使用。
塔特·约翰逊

16
注意这里!这是与其他语言的重要区别:子类中提供私有方法。private和protected的唯一区别是可以使用“ self.set_defaults”调用受保护的方法,而私有方法只能称为“ set_defaults”。
averell

一个很好的答案,但根本没有包含Rails这个词,这是问题的关键
Bryan Ash

5
注意他的问题的编辑时间戳。将来,我将定义一个私有方法来更新我的答案,因为它们会更改问题:)
EnabrenTane 2011年

正如阿弗雷尔所说,这种解释不适用于红宝石。在子类中也可以看到私有方法的地方。
Miguel 2014年

10

受保护和私有之间的区别是微妙的。如果方法受保护,则定义类或其子类的任何实例都可以调用该方法。如果方法是私有的,则只能在调用对象的上下文中调用它-即使对象与调用者属于同一类,也永远无法直接访问另一个对象实例的私有方法。对于受保护的方法,可以从相同类(或子类)的对象访问它们。

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


2
感谢您的链接。但是我想知道它们在Ruby on Rails中是如何特别工作的(公共控制器方法被视为操作方法,应用程序控制器中受保护的方法可以由其他控制器使用,等等)
jrdioko 2010年

3
在最后一种情况下,“应用程序控制器中的受保护方法可以被其他控制器使用”,这是因为其他控制器(通常)ApplicationController继承,因此它们实际上拥有所有这些方法。他们没有从application_controller访问它们:这永远不会被实例化。它纯粹用作继承的父项。
Max Williams 2010年

3

您似乎对应用于方法的类可见性(公共/受保护/私有)的语义有所了解。我所能提供的只是我在Rails应用程序中实现它的方式的简要概述。

我在基本应用程序控制器中实现了受保护的方法,因此任何控制器都可以通过过滤器(例如before_filter:method_foo)调用它们。以类似的方式,我为要在所有它们都继承的基础模型中的所有模型中使用的模型定义了受保护的方法。


2

尽管动作必须是控制器的公共方法,但并非所有公共方法都必须是动作。您可以使用hide_action,如果你使用像一个包罗万象的路线/:controller/:action/:id或者如果它是禁用(在Rails 3中默认),那么只能用显式路由方法将被调用。

如果要将控制器实例传递给Liquid模板引擎之类的其他库,这将很有用,因为您可以提供公共接口,而不必在Liquid过滤器和标签中使用send。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.