如何在 Rails 中调用 where 时避免 ActiveRecord::UnknownAttributeRefere



我有一个 Rails 应用程序,其端点接收一个结构,其中包括一堆数字:

=> #<ActionController::Parameters {"list"=>[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}], "controller"=>"items", "action"=>"total"} permitted: false>

在用.require.permit做完这些事情之后:

def purchase_list
params.require(:list).map do |list_entry|
list_entry.permit(:item_id, :quantity).to_h
end
end

我提取我需要的东西并将其存储在方法调用中的purchase_list变量中:

[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}]

然后,我想在我的数据库中查询items记录,其中id值与请求参数中的item_id数字匹配。我正在这样做:

items = Item.where(id: purchase_list.pluck(:item_id))

然后,当我尝试以任何方式使用items时,例如只是这样的东西(为简洁起见,省略了实际功能):

x = Item.first.id
items.pluck(id: x)

它崩溃并显示此错误:

ActiveRecord::UnknownAttributeReference:
Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): {:id=>425}.This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().

我一直在玩Arel.sql(),试图让它以其他方式工作,但我无法让它工作。它总是给出ActiveRecord::UnknownAttributeReference错误。

我也尝试过用to_i将它们转换为数字,但这无济于事。

但是从我在 Rails 指南和其他地方读到的内容来看,如果我使用像这样的"哈希条件"来调用wherewhere(id: [x,y,z]),这是指定 Rails 应该自动清理输入以防止 MySQL 注入之类的where条件的方法之一?我以为只有用"纯字符串"来称呼where才会让它变得脆弱?

如果有人能向我解释,我将不胜感激:

  1. 如果我使用的方法,为什么 Rails 会给我这个错误,而 Rails 应该清理输入以使其安全?
  2. 我怎样才能完成我想做的事情?用Arel.sql()或任何其他方式?

我正在使用的版本:

ruby "3.0.3"
gem "rails", "~> 7.0.3", ">= 7.0.3.1"

一定有一些你没有在这里展示的东西。我在本地尝试了该代码,它对我有用。

你能尝试在Rails控制台中运行这段代码吗?

pry(main)> params = ActionController::Parameters.new({"list"=>[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}], "controller"=>"items", "action"=>"total"})
=> #<ActionController::Parameters {"list"=>[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}], "controller"=>"items", "action"=>"total"} permitted: false>
pry(main)> purchase_list = params.permit(list: [:item_id, :quantity])[:list]
=> [#<ActionController::Parameters {"item_id"=>"417", "quantity"=>"5"} permitted: true>,
#<ActionController::Parameters {"item_id"=>"418", "quantity"=>"1"} permitted: true>,
#<ActionController::Parameters {"item_id"=>"416", "quantity"=>"2"} permitted: true>]
pry(main)> ids = purchase_list.pluck(:item_id)
=> ["417", "418", "416"]
pry(main)> Item.where(id: ids)