Rails中的受保护和私有方法

时间:2010-12-20 23:45:03

标签: ruby-on-rails ruby visibility private protected

this blog post之类的地方已经很好地解释了Ruby(公共方法,受保护方法和私有方法)中的方法可见性。但是在Ruby on Rails中,由于框架的设置方式,它似乎与常规Ruby应用程序略有不同。那么,在Rails模型,控制器,帮助器,测试等中,何时/不适合使用受保护或私有方法?

修改:感谢您的回答。我理解Ruby中的protected和private的概念,但我正在寻找更多关于在Rails应用程序的各个部分(模型,控制器,帮助程序,测试)的上下文中使用这些类型的可见性的典型方式的解释。例如,公共控制器方法是操作方法,应用程序控制器中的受保护方法用于需要由多个控制器访问的“辅助方法”等。

5 个答案:

答案 0 :(得分:102)

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

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

对于控制器和测试,只需按照您的要求进行操作即可。 控制器和测试类都只是实例化并被框架调用(是的,我知道你理论上可以从视图中获取控制器,但是如果你这样做,那么有些东西很奇怪)。由于没有人会直接创造这些东西,所以没有什么可以“保护”。

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

对于帮助者,如果方法受到保护或私有,它将没有区别,因为它们总是被“直接”调用。

当然,如果它让你更容易理解,你可以在所有这些情况下标记受保护的东西。

答案 1 :(得分:64)

如果您希望self 以外的其他人使用方法,则使用私有方法。如果你想要只有self and is_a?(self)可以调用的东西,你可以使用受保护的方法。

如果您使用“虚拟”初始化方法,可以很好地使用受保护的方法。

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会有不同的值。并且Derived实例不会有@baz

更新: 自从我写这篇文章以来,Ruby 2.0中的一些内容发生了变化.Aaron Patterson写了一篇很好的文章http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html

答案 2 :(得分:10)

  

受保护与保护之间的区别   私人是微妙的。如果方法是   受保护的,可以被任何人调用   定义类的实例或其实例   子类。如果方法是私有的,那么   可以仅在上下文中调用   调用对象---它永远不会   可以访问另一个对象   实例的私有方法直接,   即使对象是相同的   作为调用者的类。为了保护   方法,可以从中获取   同一类的对象(或   儿童)。

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

答案 3 :(得分:3)

您似乎很好地了解了应用于方法的类可见性(public / protected / private)的语义。我所能提供的只是我在Rails应用程序中实现它的方式的快速概述。

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

答案 4 :(得分:2)

虽然操作需要是控制器的公共方法,但并非所有公共方法都必须是操作。如果您使用的是/:controller/:action/:id这样的全部路由,或者如果它被禁用(Rails 3中的默认值),则可以使用hide_action,然后只调用具有显式路由的方法。

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