I have a Rails app with an endpoint receiving a structure containing, among other things, a bunch of numbers:
=> #<ActionController::Parameters {"list"=>[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}], "controller"=>"items", "action"=>"total"} permitted: false>
After doing this stuff with .require
and .permit
:
def purchase_list
params.require(:list).map do |list_entry|
list_entry.permit(:item_id, :quantity).to_h
end
end
I extract the stuff I need and store it in a purchase_list
variable from a method call:
[{"item_id"=>"417", "quantity"=>"5"}, {"item_id"=>"418", "quantity"=>"1"}, {"item_id"=>"416", "quantity"=>"2"}]
I then want to query my database for items
records with id
values matching those item_id
numbers in the request params. I'm doing this:
items = Item.where(id: purchase_list.pluck(:item_id))
Then when I try to use items
in any way, for example just something like this (real functionality omitted for brevity):
x = Item.first.id
items.pluck(id: x)
It crashes with this error:
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().
I've been playing around with Arel.sql()
to try and make it work some other way, but I can't get it working. It always gives that ActiveRecord::UnknownAttributeReference
error.
I've also tried converting them to numbers with to_i
and it won't help.
But from what I've read in the Rails guides and other places, if I'm calling where
using the "hash conditions" like this where(id: [x,y,z])
, that's one of the ways of specifying where
conditions for which Rails should automatically sanitise the inputs to guard against MySQL injections and that sort of thing? I thought only calling where
with "pure strings" made it vulnerable?
I would be very grateful if someone could explain to me:
- Why is Rails giving me that error if I'm using an approach for which Rails should sanitise the input to make it safe?
- How can I accomplish what I'm trying to do? with
Arel.sql()
or any other way?
I'm using versions:
ruby "3.0.3"
gem "rails", "~> 7.0.3", ">= 7.0.3.1"
CodePudding user response:
There must be something you're not showing here. I tried that code locally and it works for me.
Could you try to run this code in Rails console?
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)