Ruby on rails 为什么ActiveRecord在初始化后和查找回调后文档提到块级别变量?
我在我的Ruby on rails 为什么ActiveRecord在初始化后和查找回调后文档提到块级别变量?,ruby-on-rails,ruby,Ruby On Rails,Ruby,我在我的用户模型中定义了一个后初始化和一个后查找回调: 请假设我的用户也有一个名为电子邮件的属性 class User < ApplicationRecord after_initialize do |user| puts "You have initialized an object! Email: #{email}" end after_find do |user| puts "You have found an object! Email: #{emai
用户
模型中定义了一个后初始化
和一个后查找
回调:
请假设我的用户
也有一个名为电子邮件
的属性
class User < ApplicationRecord
after_initialize do |user|
puts "You have initialized an object! Email: #{email}"
end
after_find do |user|
puts "You have found an object! Email: #{email}"
end
end
我的问题是,为什么回调的文档中提到存在块局部变量
user
?正如我在上面所经历的,虽然没有使用用户
局部变量,但我仍然可以访问实例化的用户
实例和/或查找的实例。这些没有记录项
的回调(在您的例子中是用户
实例)的意义要小得多(如果有的话)-除了测试目的(如您刚刚通过调用puts
确认已找到记录时的情况)之外,通常情况下,在实际用例中,您可能需要在应用程序中使用该对象之前读取/修改该对象
因此,当您定义回调时,ActiveRecord
将它们存储在内部ActiveRecord
假设您将需要此实例,并且在调用块时do。。。结束
,它使用找到的记录(用户
)来完成。
理论上(我没有在ActiveRecord
codebase中检查实际实现)可能看起来像:
record = find_record
if after_find_callback
after_find_callback.call(record)
end
它不是必需的,是可选的。您可以执行以下任一操作并获得相同的结果。假设User
具有:name
属性:
after_initialize do |user|
puts user.name
end
after_initialize do
puts name
end
我猜文档使用了| user |
变量,因为当有显式接收器时,它更清晰,特别是对于新的Ruby/Rails开发人员
换句话说,第一个选项不会改变执行的上下文(或“词法范围”)和self
的定义,而第二个选项会改变,这一点一开始可能会让人困惑。我认为它只是用于文档,这样人们就可以知道块内发生的事情是针对用户的,是的,它实际上没有被使用
您可以在不使用用户
变量的情况下定义:
after_initialize do
puts "You have initialized an object! Email: #{email}"
end
从:
以及:
所以,块的变量是什么并不重要
顺便说一句,您也可以像其他回调一样使用方法而不是块来使用after\u initialize
(after\u save,after\u create
):
检查活动记录回调和ActiveRecord::Callbacks
。已经检查了,请不要忽略sandno。这不是必需的。我已经修改了问题的内容,以证明它不是必需的。那么为什么不直接回答问题呢?你随意编辑了那个问题,因为我没有时间搜索/调查文档中有这个user
block-level变量的原因。同时,我看到@thanh发布了一个答案,这可能是一个好答案。它读起来和最初的问题完全不同,以至于他们需要不同的答案@p.matsinopoulost这是不正确的。我已经修改了问题内容,以表明user
block-level变量是无用的。您仍然可以访问正在初始化和/或找到的实例。这不是正确的源代码。您正在查看Railtie初始值设定项的源代码。@m.simonborg您是否尝试过在上面的代码初始化后调试,以查看它的去向?在初始化
后尝试而不使用user
变量?我已经研究了ActiveRecord回调的实现,您引用的代码不是它。我从不直接将块传递给回调方法,但更喜欢传递符号。我不在乎是否将回调与块或方法一起使用!我的问题是“你有没有在用块初始化后尝试,以查看实际运行的代码以及它从哪里开始”,而不是仅仅查看实现过程?OP询问的是块,而不是方法引用(符号)。是的,我将它与块一起使用,以查看运行的是什么。如果您希望在实例的上下文中执行块(即更改self
的值),但也可以选择显式接收器(如当前示例中,|user |
是可选的),则可以使用base.instance_eval(&block)
,而不是block.call(base)
<代码>块。调用(base)
需要块中的显式变量。除此之外,ActiveRecord回调肯定不会在Railtie::Configuration
中实现。另外,初始化后的ActiveRecord占用的参数比一个块多。
after_initialize do
puts "You have initialized an object! Email: #{email}"
end
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, yield: true, &block)
end
# Declares a block that will be executed when a Rails component is fully
# loaded.
def on_load(name, options = {}, &block)
@loaded[name].each do |base|
execute_hook(base, options, block)
end
@load_hooks[name] << [block, options]
end
def execute_hook(base, options, block)
if options[:yield]
block.call(base)
else
base.instance_eval(&block)
end
end
if options[:yield]
block.call(base)
...
after_initialize :after_initialize_method
def after_initialize_method
puts "You have initialized an object! Email: #{email}"
end