我已在after_initialize
模型中定义了after_find
和User
回调:
请假设我的User
也有一个名为email
的属性。
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
遵循我在Rails Guides。
中找到的文档这可以按预期工作。即当我拨打User.new
或User.first
时,我看到输出按预期打印:
2.3.3 :001 > User.new(email: 'foo@gmail.com')
You have initialized an object! Email: foo@gmail.com
=> #<User id: nil, email: "foo@gmail.com", password_digest: nil,
created_at: nil, updated_at: nil, email_confirmation_token: nil,
terms_of_service: false, country_id: nil>
2.3.3 :002 > User.first
User Load (0.6ms) SELECT "users".* FROM "users" ORDER BY "users"."id"
ASC LIMIT $1 [["LIMIT", 1]]
You have found an object! Email: mary@gmail.com
You have initialized an object! Email: mary@gmail.com
=> #<User id: 10, email: "mary@gmail.com", password_digest:
"$...", created_at: "2017-06-10 06:46:05", updated_at: "2017-07-02
09:52:46", email_confirmation_token: "yStnErkVCFC9mYNHKFNYdA",
terms_of_service: true, country_id: nil>
我的问题是为什么回调文档中提到了块局部变量user
的存在?正如您从上面所经历的那样可以看出,user
局部变量未被使用,但我仍然可以访问实例化的User
实例和/找到的实例。
答案 0 :(得分:0)
这些没有record item
的回调(在你的情况下是一个user
实例)会有更少的意义(如果有的话) - 除了测试目的,就像你刚刚确认自己的记录有通过调用puts
找到,通常情况下,在实际使用案例中,您可能需要在您的应用中使用此对象之前进行阅读/修改。
因此,当您定义回调时,ActiveRecord
会在内部存储它们。 ActiveRecord
假定您需要此实例,并且在调用块do ... end
时,它会使用找到的记录(user
)执行此操作。
理论上(我没有检查ActiveRecord
代码库中的实际实现)可能看起来像:
record = find_record
if after_find_callback
after_find_callback.call(record)
end
答案 1 :(得分:0)
这不是必需的,它是可选的。您可以执行以下任一操作并获得相同的结果。假设User
具有:name
属性:
after_initialize do |user|
puts user.name
end
after_initialize do
puts name
end
我的猜测是文档使用|user|
变量,因为它更清晰,特别是对于新的Ruby / Rails开发人员,当有明确的接收者时。
换句话说,第一个选项不会改变执行的上下文(或“词法范围”)和self
的定义,而第二个选项会改变,这可能会让人感到困惑。< / p>
答案 2 :(得分:-1)
我认为它只是用于文档,因此人们可以知道块内部发生的事件是user
的目标,是的,实际上并没有使用它。
您可以定义不含user
变量:
after_initialize do
puts "You have initialized an object! Email: #{email}"
end
来自after_initialize source code:
def after_initialize(&block)
ActiveSupport.on_load(:after_initialize, yield: true, &block)
end
和source code of on_load method:
# 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
因为选项yield: true
,将在execute_hook
方法中调用该块:
if options[:yield]
block.call(base)
...
所以,你的变量是什么并不重要。
顺便说一下,您也可以使用after_initialize
方法代替阻止,就像其他回调一样(after_save, after_create
):
after_initialize :after_initialize_method
def after_initialize_method
puts "You have initialized an object! Email: #{email}"
end