Rails——自我与@

发布于 2024-11-15 03:53:40 字数 1750 浏览 3 评论 0原文

我正在关注 Michael Hartl 的 RoR 教程,它涵盖了密码加密的基础知识。这是当前的用户模型:

class User < ActiveRecord::Base
    attr_accessor :password

    attr_accessible :name, :email,: password, :password_confirmation

    email_regex = /^[A-Za-z0-9._+-]+@[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+[A-Za-z]$/
                                              #tests for valid email addresses.

    validates :name, :presence => true,
                     :length => {:maximum => 50}
    validates :email, :presence => true,
                      :format => {:with => email_regex},
                      :uniqueness => {:case_sensitive => false}
    validates :password, :presence => true,
                         :length => {:maximum => 20, :minimum => 6},
                         :confirmation => true

    before_save :encrypt_password

    private

    def encrypt_password
        self.encrypted_password = encrypt(password)
    end

    def encrypt(string)
        string
    end
end

我之前发布了一个关于 before_save 不起作用的问题,结果发现我不小心所做的是将我的 encrypt_password 写为:

def encrypt_password
    @encrypted_password = encrypt(password)
end

我明白如果 self.encrypted_pa​​ssword设置了 crypto_password 属性,但为什么 @encrypted_pa​​ssword 不这样做呢?在对上一篇关于 before_save 不起作用的帖子的回复中,有人说在该方法以我最初编码的方式结束后,实例变量被“遗忘”——为什么会出现这种情况?有人可以解释一下 self 和 @ 在上面代码的上下文中如何不同工作吗?

注意:我已经看过这些帖子 这里这里,但它们都是说“自己”正在调用 attribute = 方法,我什至不明白该方法如何存在于此处,因为我从未创建它或使用 attr_accessor 声明加密的密码。所以我仍然很困惑,这不是这些问题的重新发布。

I am following Michael Hartl's RoR tutorial, and it is covering the basics of password encryption. This is the User model as it currently stands:

class User < ActiveRecord::Base
    attr_accessor :password

    attr_accessible :name, :email,: password, :password_confirmation

    email_regex = /^[A-Za-z0-9._+-]+@[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+[A-Za-z]$/
                                              #tests for valid email addresses.

    validates :name, :presence => true,
                     :length => {:maximum => 50}
    validates :email, :presence => true,
                      :format => {:with => email_regex},
                      :uniqueness => {:case_sensitive => false}
    validates :password, :presence => true,
                         :length => {:maximum => 20, :minimum => 6},
                         :confirmation => true

    before_save :encrypt_password

    private

    def encrypt_password
        self.encrypted_password = encrypt(password)
    end

    def encrypt(string)
        string
    end
end

I posted a previous question about before_save not working, and it turns out that what I had accidentally done is written my encrypt_password as:

def encrypt_password
    @encrypted_password = encrypt(password)
end

I understand that if self.encrypted_password sets the encrypted_password attribute, but why does @encrypted_password not do that as well? In the response to the previous post about before_save not working someone said that the instance variable was "forgotten" after the method ended with the way I had originally coded it -- why was this the case? Can someone please explain how self and @ work differently in the context of the code above?

NOTE: I already took a look at the posts here and here, but they both say that "self" is calling the attribute = method, and I don't even understand how that method could exist here since I never created it or declared the encrypted_password w/ attr_accessor. So I am still confused, and this is not a re-posting of those questions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一身软味 2024-11-22 03:53:40

Rails 已自动为您添加 encrypted_pa​​ssword 的访问器,因为 users 表中存在具有该名称的字段。

您添加到表中的任何字段都将通过 self.field_name 自动提供。

此处是 Michael Hartl 的教程在以下位置创建 encrypted_pa​​ssword 字段的位置users

另请查看链接页面中的user_spec.rb(清单7.3),其中作者正在测试encrypted_pa​​ssword字段是否存在。

更新:

正如 @mu 指出的,@ 用于 Ruby 实例变量(又名“iv”)。但encrypted_pa​​ssword是Rails定义的“属性”,而不是实例变量。

如果运行User.find(1).instance_variables,您将看到有一个名为@attributes的iv,其类型为Hash

在该 iv 内是存储 encrypted_pa​​ssword 的地方。 Rails 为 encrypted_pa​​ssword 定义了访问器方法,用于获取/设置该密码的数据
@attributes Hash 中的属性。

请注意,您还可以通过从 User 类中调用的 @attributes["encrypted_pa​​ssword"] 获取/设置数据(但访问器方法是执行此操作的便捷方法) )。

The accessors for encrypted_password have been automatically added by Rails for you because a field by that name exists in the users table.

Any field you add to a table will be automatically made available via self.field_name.

Here is where Michael Hartl's tutorial creates the encrypted_password field in the users table.

Also look at the user_spec.rb (Listing 7.3) in the linked page, where the author is testing for the presence of the encrypted_password field.

UPDATED:

As @mu points out, the @ is used for Ruby instance variables (aka "iv"). But encrypted_password is an "attribute" defined by Rails, and is not an instance variable.

If you run User.find(1).instance_variables, you will see that there is an iv called @attributes, which is of type Hash.

Inside that iv is where the encrypted_password is stored. Rails has defined accessor methods for encrypted_password, which gets/sets the data for that
attribute in the @attributes Hash.

Note that you could also get/set the data via @attributes["encrypted_password"] called from within the User class (but the accessor methods are convenient way to do just that).

月依秋水 2024-11-22 03:53:40

如果你允许的话,我想重新表述一下答案。

我在这篇帖子中解释说,一旦您创建一个与数据库的(复数)表名之一具有相同(单数)名称的(rails-)模型,rails 的“魔力”将创建setter 和 getter 以便修改表的记录。

这是因为您的模型继承了 ActiveRecord::Base 类的所有方法,该类定义了基本的 CRUD 访问器(创建、读取、更新、删除)。

与您的问题相关的关键点是,您不知道rails如何实现与数据库表列相关的实例变量,而且您不应该这样做。 :) 您需要知道的是,此时您已经拥有可用于 CRUD(创建、读取、更新、删除)数据库列“加密密码”的 setter 和 getter。

在您的示例中,也许rails使用名为 @encrypted_pa​​ssword的实例变量,也许rails使用名为 @attributes[“encrypted_pa​​ssword”]的哈希实例变量,或者也许rails使用了一个名为@you_will_never_guess_encrypted_pa​​ssword的实例变量。

-

这是一个很好的观点,你不知道实例变量的内部 Rails 行为。 2019 年,Rails 的进一步开发可能会导致框架使用 @complicated-hash-instance-variable 来存储 cryptod_password 值。

事实上,最好的方法是让 Rails 使用实例变量来管理其“私有”“事务”;),并且只使用它提供给您的 getter 和 setter 方法。
因此,您的应用程序在下个世纪仍将使用 crypto_password(我希望如此 ^^)。

因此,如果您使用@encrypted_pa​​ssword,它可能适用于某些“虚构”版本的rails,并且不再适用于其他rails版本。实际上,对于当前版本的 Rails 来说,它不起作用。

-

第二个关键点是,当您想要使用为 crypto_password 数据库表列创建的 getter“encrypted_pa​​ssword”Rails 时,您可以在其前面加上“self< /strong>”,以便告诉 Ruby:“好吧,我想使用我的 User 实例变量的 crypto_password 方法。”

在 Ruby 中,通过将方法的名称传递给接收者来调用方法。
您可以这样编写:

my_receiver.my_method

在您的情况下,我们将方法 encrypted_pa​​ssword 传递给 User 实例变量。但我们不知道这个实例变量将如何命名,因此我们使用单词 self 告诉 Ruby:“我正在谈论 User 的任何实例变量调用 crypto_password 方法的类”。

例如,我们可以将实例变量命名为“toto”:

toto = User.new

这样toto.encrypted_pa​​ssword将显示加密的密码,而在这种情况下,我们的代码中的self将引用toto。

然而,多亏了 Ruby,如果您在调用方法时没有提供任何接收者,Ruby 会假设您将其传递给 self

参考: 实用程序员指南

因此,在您的示例中,您甚至不需要加上“自我”。作为前缀。
你可以这样写:

class User < ActiveRecord::Base

    def encrypt_password
        encrypted_password = encrypt(password)
    end
end

我希望这有助于澄清这个有趣的主题。

If you let me, I'd like to rephrase the answer.

I explained in this post, that as soon as you create a (rails-) Model with the same (singular) name as one of the (plural) tablenames of your database, the "magic" of rails will create setters and getters in order to modify your table's records.

This is because your model inherits all methods from the ActiveRecord::Base Class, which defines basic CRUD accessors (Create, Read, Update, Delete).

The key point related to your question, is that you don't know how rails implements the instance variable related to your database table column, And you shouldn't. :) All you have to know is that at that point, you have setters and getters available to CRUD (create, read, update, delete) your database column "encrypted_password".

In your example, maybe rails uses an instance variable called @encrypted_password, maybe rails uses an hash-instance-variable called @attributes["encrypted_password"], or maybe rails uses an instance variable called @you_will_never_guess_encrypted_password.

-

And that's a good point you don't know about the internal rails behavior with instance variables. In 2019 Rails further development may lead the framework to use @complicated-hash-instance-variable to store the encrypted_password value.

In fact the best approach is to let rails manage its "private" "affair" ;) with instance variables, and just use the getter and setter methods it provides to you.
So your application will still work with encrypted_password in the next century (I hope so ^^).

So if you use @encrypted_password it may work with some "imaginary" version of rails and it won't work anymore with other rails versions. Actually with a current version of rails it doesn't work.

-

The second key point is that when you want to use the getter "encrypted_password" Rails created for your encrypted_password database table column, you prefix it with "self" in order to tells Ruby : "ok I want to use the encrypted_password method of my User instance variable."

In Ruby, a method is called by passing its name to a receiver.
You write it like this :

my_receiver.my_method

In your case we pass the method encrypted_password to the User instance variable. But we don't know how this instance variable will be named, so we use the word self to tell Ruby : "I'm talking about any instance variable of the User class that calls the encrypted_password method".

For instance we could have named our instance variable "toto" :

toto = User.new

so toto.encrypted_password would display the encrypted password, and self in this very case in our code would reference toto.

However, thanks to Ruby, if you don't give any receiver when calling a method, Ruby will assume you pass it to self.

Reference : Pragmatic Programmer's guide

So in your example, you even don't need to put "self." as prefix.
You could have it written like this :

class User < ActiveRecord::Base

    def encrypt_password
        encrypted_password = encrypt(password)
    end
end

I hope this helps to clarify this interesting subject.

避讳 2024-11-22 03:53:40

TL;DR -

如果您打算将 widget_count 保存回数据库,请始终写入 self.widget_count = 123

(但请务必阅读长答案,因为了解其原因很有价值。)

TL;DR -

Always write self.widget_count = 123 if you intend to save widget_count back to the database.

(But please do read the long answers, as the reason why is valuable to know.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文