这是从头开始在Rails Casts#250身份验证中的代码:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
...
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
在encrypt_password
,为什么当生成password_hash
的参数传递到hash_secret
是password_salt
不是self.password_salt
?为什么在这种情况下会自动识别实例变量?
Ruby具有后备机制。考虑以下示例:
class SomeClass
def my_method
"my method"
end
def other_method_with_local_variable
my_method = "lala"
puts my_method
end
def other_method
my_method
end
end
现在让我们在控制台中测试这些方法:
1.9.3p448 :016 > SomeClass.new.other_method # outputs instance method value, because there were none local variables inside the method and it falled back to instance scope
=> "my method"
1.9.3p448 :017 > SomeClass.new.other_method_with_local_variable # outputs "lala" because it's the value of lcoal variable
lala
不了解此概念的人经常过度使用self
它,这会使经验丰富的Ruby开发人员流血:D
UPD
看来您正在将实例方法与实例变量混淆。如果您来自其他OOP语言,则最类似于实例var的是私有属性/属性。当然,在Ruby中,可以通过一些变通办法来实现它。例子:
class Person
def initialize(name)
@name = name
end
end
p = Person.new("John")
# => #<Person:0x007fbe910cc680 @name="John">
p.name #produces error, because object doesn't have such method, only a private property
#NoMethodError: undefined method `name' for #<Person:0x007fbe910cc680 @name="John">
p.instance_variables # we can always get list of instance variables
# => [:@name]
p.instance_variable_get(:@name) # access them
# => "John"
p.instance_variable_set(:@name, "Ben") # and set them
# => "Ben"
p
# <Person:0x007fbe910cc680 @name="Ben">
用这种方式弄乱对象内部结构被认为是一个非常不好的习惯,我们应该使用该类的公共接口。在许多语言中,通常人们开始为此类属性定义访问器/设置器。这是相当普遍看到这样的方法set_name
,get_name
内部类。Ruby语法允许,并且约定建议采用这种方式:
class Person
def initialize(name)
@name = name
end
def name
@name
end
def name=(new_name)
@name = new_name
end
end
1.9.3p448 :015 > p = Person.new("John")
# => #<Person:0x007f8b8b20ad28 @name="John">
1.9.3p448 :016 > p.name
# => "John"
1.9.3p448 :017 > p.name = "Ben"
# => "Ben"
1.9.3p448 :018 > p
# => #<Person:0x007f8b8b20ad28 @name="Ben">
在对象中定义它们很常见,因此Ruby为此提供了快捷方式。我们可以像这样重构我们的班级:
class Person
attr_accessor :name
def initialize(name)
@name = name
end
end
1.9.3p448 :009 > p = Person.new("John")
# => #<Person:0x007f8091233a48 @name="John">
1.9.3p448 :010 > p.name
# => "John"
1.9.3p448 :011 > p.name = "Ben"
# => "Ben"
1.9.3p448 :012 > p
# => #<Person:0x007f8091233a48 @name="Ben">
我们实际上可以验证它attr_accessor
是否完全相同:
1.9.3p448 :013 > Person.instance_methods.grep(/^name=?/)
# => [:name, :name=]
现在回到ActiveRecord。它以与您的列相同的方式定义方法,因此对于name
列,它将定义方法name
和name=
。区别在于,AR对象要复杂得多,并且那些调用读/写属性的作用不只是设置实例变量@name
。
如果您了解变量/方法范围的概念,那么应该清楚何时使用self
以及这些方法调用的实际用途。
小总结:
self
self
在写入accessor(self.name =
)时需要明确地说,否则Ruby会将其视为本地变量的创建。self
如果您在本地范围内具有相同名称的变量,则在读取时还需要使用,但这是非常不好的做法,我怀疑您会遇到这种情况。本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句