我一直在关注教科书并构建一个简单的RoR应用程序。令我困惑的一件事是,似乎模块中的变量以某种方式由控制器访问,包含它而没有任何访问器。这是模块:
module CurrentCart
extend ActiveSupport::Concern
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
和控制器调用它
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
....
def create
@product = Product.find(Params[:prouct_id])
@line_item = @cart.line_items.build(product: product)
...
end
你看到了吗? @cart正在使用它可以访问的变量。我对Ruby和Rails都很陌生,但有人可以解释一下这是可能的吗?
感谢
答案 0 :(得分:5)
在类中包含一个模块会扩展该类,以包含模块的方法和实例变量(至少已经设置过的那些)。在这种情况下,@ cart在控制器中可用,因为a)已包含模块,b)有一个调用set_cart
方法(设置@cart)的before_action。
一旦包含它,您基本上可以将模块的内容视为直接出现在控制器中。这并不完全正确,因为当方法被提取到模块中时,您有机会在类中覆盖它们,但是为了您的情况,它仍然存在。
编辑以澄清:您不需要访问者,因为模块的方法和ivars属于控制器类的同一个实例。
答案 1 :(得分:1)
首先,您使用的条款不正确。 @my_var = 1
设置实例(!)变量,而my_var = 1
声明并设置局部变量。实例变量属于对象,并且始终可以在其中访问。局部变量只能在声明它们的上下文中访问。
现在关于include
。长篇短include
将您的模块添加到类层次结构中,因此您可以将其视为“类似继承”。所以在你的代码中@cart
不是模块的实例变量,它是一个对象的实例变量,类定义包含你的模块。
如果您需要详细信息,请阅读文章。 http://tech.pro/tutorial/1149/understanding-method-lookup-in-ruby-20
最后,rails helper before_action
介入并调用在执行操作之前列出的方法。
答案 2 :(得分:-1)
没有。您必须在模块中为此提供方法
module CurrentCart
extend ActiveSupport::Concern
def create_line_items(product)
@cart.line_items.build(product: product)
end
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
和
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
....
def create
@product = Product.find(Params[:prouct_id])
@line_item = create_line_items(@product)
...
end