我有一个简单的控制器方法:
products = Product.where(name: name, color: color, size: size, available: true)
返回Product :: ActiveRecord_Relation对象。我想拿第一个物体然后拉出一个例如products.first.product_code
但我和其他一些尝试重新查询数据库的方法。我试过了:
products[0].product_code
products.take.product_code
所有这些都重新查询数据库,两次击中数据库。一次为了哪里和一个采取领域。有没有一个简单的解决方案不会打击数据库?
将ActiveRecord转换为数组(products.to_a.[0].product_code
)的工作原理是什么,但这似乎效率低下。
以下是显示两个单独匹配的服务器日志:
这是我的控制器方法供参考:
def update_selection
size = params[:size]
color = params[:color]
name = params[:product_name]
products = Product.where(name: name, color: color, size: size, available: true)
product_code = products.empty? ? 'sold out' : products.first.product_code
respond_to do |format|
format.json { render json: { count: products.length, code: product_code}}
end
end
答案 0 :(得分:4)
我最好的猜测是,在分配给products
时,您实际上并没有访问数据库。 ActiveRecord关系是惰性的,这意味着在需要该查询的结果之前,它们不会查询数据库。
根据您的问题加以说明 - 这一行:
products = Product.where(name: name, color: color, size: size, available: true)
不需要实际从数据库中提取任何数据,因此不执行查询。
另一方面, products.first.product_code
将导致查询触发。
编辑:
我认为问题来自于使用.exists?
(这是总是触发查询的ActiveRecord方法)。如果您要检查查询是否返回了任何结果,请尝试使用.present?
或.any?
代替.exists?
。
编辑2:
好的,谢谢您发布代码。你在这里有几个选择。
.to_a
: products = Product.where(name: name, color: color, size: size, available: true).to_a
这会将所有products
加载到内存中,如果您预计会有少量产品,这是有意义的。这只会触发一个查询。
product_code = products.first.try(:product_code) || 'sold out'
这样可以提高内存效率(因为您最多只能将product
加载到内存中),但使用了两个查询(products.count is the other one
)。
答案 1 :(得分:1)
您可能会发现这是有效的,因为它获得了基于SQL的计数,然后在需要获得单个产品时重新运行产品查询。
你真的想要ID最低的那个“第一”吗?如果是,请使用first
,否则请使用take
。
def update_selection
size = params[:size]
color = params[:color]
name = params[:product_name]
products = Product.where(name: name, color: color, size: size, available: true)
product_count = products.count
product_code = product_count.zero? ? 'sold out' : products.take.product_code
respond_to do |format|
format.json { render json: { count: product_count, code: product_code}}
end
end