我在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
。如何在许多其他类中使用它?
答案 0 :(得分:2)
@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 ....在一个小的初学者代码库中它没关系。
答案 1 :(得分:0)
这大致意味着如果@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
必须再次点击数据库(缓存除外)。如果可以的话,你想避免这种情况。那么,为什么不将用户存储在全局实例变量中呢?
因此:
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
答案是,您在同一请求/响应中执行此操作以进行可重用性抖动。