我在Ruby on Rails应用程序中看到了这段代码:
module SessionsHelper
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
...
end
为什么在current_user
方法中使用实例变量而不是局部变量?当我将其更改为局部变量时,一切都与使用实例变量相同。
我读到一个实例变量可以用在包含这个模块的许多其他类中。但在这种情况下,它们是用current_user
方法定义的,用于存储用户的值@current_user
。这在其他许多课程中如何使用?
这大致意味着如果已经定义了@current_user
作为全局请求/响应范围(Controller / View / Helpers)的实例变量,则将其用作current_user
。否则,为其分配与会话中存储的id对应的用户执行的操作。
换句话说,这类似于:
def current_user
if @current_user # this will be false in every hit, for the same request
@current_user
else
User.find_by id: session[:user_id]
end
end
这应该足够了。
但是,你可以在代码的其他部分再次使用current_user
,让我们在控制器中说同样的请求。
这意味着,current_user
将不得不再次击中DB(缓存除外)。如果可以的话,你想避免这种情况。那么,为什么不将用户存储在全局实例变量中呢?
从而:
def current_user
if @current_user # this will be false for the first hit, true for every subsequent request
@current_user
else
@current_user = User.find_by id: session[:user_id]
end
end
既然我们这样做,为什么不使用速记方法呢?
所以,最后:
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
答案是,您在同一请求/响应中执行此操作以进行可重用性抖动。
@current_user || = User.find_by id:session [:user_id]
这里使用了一些Ruby快捷方式,所以让我们扩展为:
if @current_user == nil
@current_user = User.find_by id: session[:user_id]
end
return @current_user
太好了。但是这个数据库查找实际上可能需要很长时间(比如我们每次调用它都需要几十毫秒)。这可能不会感觉很长时间,但它最终会加起来--Rails应用程序会调用当前用户(仅请求一次与几十次也会减少数据库服务器上的负载)。 (没有任何类型的缓存ActiveRecord和Rails正在你背后做......
因此,我们将结果保存到我们以后的实例变量中。
因此,如果您在current_user方法中执行了类似的操作
if my_current_user
my_current_user = User.find_by id: session[:user_id]
end
return my_current_user
这将始终进入if
语句,始终执行查找,将答案放在本地并返回它。下次它不知道它已经查找了,所以将再次进行相同的数据库查询,获得结果等等。所以它可能会工作,但它会比在这里使用实例变量慢。
当然,有一个缺点。 Ruby中的模块可以导入到类中 - 模块中的方法成为类的方法。所以是的,现在您已经为导入模块的所有类创建了一个实例变量。这是......可能不完全友好(如果其他一些模块也使用该名称会怎么样?),但是ehhhhhhhhhhh ....在一个小的初学者代码库中它并不重要。