模型before_save中的变量范围

一零

这是从头开始在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_secretpassword_salt不是self.password_salt为什么在这种情况下会自动识别实例变量?

埃德加斯(Edgars Jekabsons)

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_nameget_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列,它将定义方法namename=区别在于,AR对象要复杂得多,并且那些调用读/写属性的作用不只是设置实例变量@name

如果您了解变量/方法范围的概念,那么应该清楚何时使用self以及这些方法调用的实际用途

小总结:

  • 实例var不是方法,它们可以称为对象的私有属性
  • 我们定义访问器方法来访问实例变量,通常使用attr_accessor,attr_reader(只读属性)方法
  • 当访问某些变量时,Ruby在本地范围内搜索变量,如果找不到,则Ruby会以为它是实例方法并对其进行调用 self
  • self在写入accessor(self.name =需要明确地说,否则Ruby会将其视为本地变量的创建。self如果您在本地范围内具有相同名称的变量,则在读取时还需要使用,但这是非常不好的做法,我怀疑您会遇到这种情况。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在相关模型中的属性更改后运行before_save

来自分类Dev

在相关模型中更改属性后运行before_save

来自分类Dev

了解Ruby / Rails中的before_save

来自分类Dev

在before_save中设置参数

来自分类Dev

Rails-在before_save中获取旧值

来自分类Dev

如何验证在before_save中更改的数据

来自分类Dev

在before_save回调中修改子记录

来自分类Dev

模型before_save不使用来自参数/控制器的更新的多选顺序

来自分类Dev

Rails:`before_save`会干扰`save?`

来自分类Dev

Peewee ORM中的before_save()和after_save()挂钩?

来自分类Dev

Peewee ORM中的before_save()和after_save()挂钩?

来自分类Dev

具有嵌套属性创建的模型更改了before_validation和before_save之间的关联类型属性

来自分类Dev

处理before_save导轨的智能方法

来自分类Dev

回形针,before_save和删除附件

来自分类Dev

before_save,去除字符串

来自分类Dev

Ruby on Rails:before_save字段小写

来自分类Dev

Smart way to handle before_save rails

来自分类Dev

验证后是否运行before_save?

来自分类Dev

Rails before_save无法正常工作

来自分类Dev

Before_save不运行滑轨4

来自分类Dev

多次创建 before_save 调用

来自分类Dev

Rails 4:如何取消“ before_save”回调中的保存?

来自分类Dev

为什么this before_save无法更新Rails中的验证日期?

来自分类Dev

Rails:为什么调用parent上的before_save?

来自分类Dev

在Rails before_save方法中大写多个属性

来自分类Dev

before_save是否为attribute.present?

来自分类Dev

Rails:before_save大写私有方法

来自分类Dev

在rails 6上未触发before_save回调

来自分类Dev

Rails:为什么调用parent上的before_save?

Related 相关文章

热门标签

归档