Ruby 为什么在模块中使用实例变量而不是局部变量?

Ruby 为什么在模块中使用实例变量而不是局部变量?,ruby,memoization,Ruby,Memoization,我看到了Ruby on Rails应用程序的以下代码: module SessionsHelper def current_user @current_user ||= User.find_by id: session[:user_id] end ... end 为什么在current\u user方法中使用实例变量而不是局部变量?当我将其更改为局部变量时,一切都与使用实例变量相同 我读到一个实例变量可以在包含这个模块的许多其他类中使用。但在这种情况下,它们是在存储用户值

我看到了Ruby on Rails应用程序的以下代码:

module SessionsHelper
  def current_user
    @current_user ||= User.find_by id: session[:user_id]
  end

  ...
end
为什么在
current\u 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都是在你背后做的那就是

因此,我们将结果保存到一个实例变量中,供以后使用

因此,如果您这样做,那么在您当前的用户方法中

if my_current_user
  my_current_user = User.find_by id: session[:user_id]
end

return my_current_user
这将始终进入
if
语句,始终执行查找,将答案放在本地并返回。下次它不知道它已经查找了,因此将再次执行相同的数据库查询,获取结果等。因此它可能会工作,但比在此处使用实例变量要慢


当然,还有一个缺点。Ruby中的模块可以导入到类中-模块中的方法成为类的方法。因此,是的,现在您已经为导入模块的所有类创建了一个实例变量。这…可能不完全是类(如果其他模块也使用该名称呢??),但在一个小的初学者代码库中,这并不重要。

这大致意味着如果
@current\u user
,作为全局请求/响应范围(Controller/View/Helpers)的实例变量,已定义,请将其用作
当前用户
。否则,请为其指定与会话中存储的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
    @current_user ||= User.find_by id: session[:user_id]
end
答案是,您这样做是为了在相同的请求/响应中实现可重用性

def current_user
    @current_user ||= User.find_by id: session[:user_id]
end