为什么在模块中使用实例变量而不是局部变量?
Why is an instance variable used instead of a local variable in a module?
我在 Rails 应用程序上看到 Ruby 的代码:
module SessionsHelper
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
...
end
为什么在current_user
方法中使用实例变量而不是局部变量?当我将其更改为局部变量时,一切都与使用实例变量相同。
我读到实例变量可以用于包含此模块的许多其他 类。但在本例中,它们定义在current_user
方法中,用于存储用户的值@current_user
。这在许多其他 类 中是如何使用的?
@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
语句,始终进行查找,将答案放在本地并 return 它。下次它不知道它已经查找了它,所以将再次执行相同的数据库查询,获取结果等等。所以它可能会工作,但它会比在这里使用实例变量慢。
当然有缺点。 Ruby 中的模块可以导入 classes - 模块中的方法成为 class 的方法。所以是的,现在您已经为导入模块的所有 classes 创建了一个实例变量。这...可能不完全友好(如果其他一些模块也使用该名称怎么办??),但是 ehhhhhhhhhhh... 在小型初学者代码库中这无关紧要。
这大概的意思是,如果@current_user
,作为全局request/response作用域(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
既然我们这样做了,为什么不使用 shorthand 方法呢?
所以,最后:
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
答案是,在相同的 request/response.
中,您这样做是为了提高可重用性
我在 Rails 应用程序上看到 Ruby 的代码:
module SessionsHelper
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
...
end
为什么在current_user
方法中使用实例变量而不是局部变量?当我将其更改为局部变量时,一切都与使用实例变量相同。
我读到实例变量可以用于包含此模块的许多其他 类。但在本例中,它们定义在current_user
方法中,用于存储用户的值@current_user
。这在许多其他 类 中是如何使用的?
@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
语句,始终进行查找,将答案放在本地并 return 它。下次它不知道它已经查找了它,所以将再次执行相同的数据库查询,获取结果等等。所以它可能会工作,但它会比在这里使用实例变量慢。
当然有缺点。 Ruby 中的模块可以导入 classes - 模块中的方法成为 class 的方法。所以是的,现在您已经为导入模块的所有 classes 创建了一个实例变量。这...可能不完全友好(如果其他一些模块也使用该名称怎么办??),但是 ehhhhhhhhhhh... 在小型初学者代码库中这无关紧要。
这大概的意思是,如果@current_user
,作为全局request/response作用域(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
既然我们这样做了,为什么不使用 shorthand 方法呢?
所以,最后:
def current_user
@current_user ||= User.find_by id: session[:user_id]
end
答案是,在相同的 request/response.
中,您这样做是为了提高可重用性