In my Ruby on Rails application i have the following params:
{"0"=>{"from_days"=>"1", "to_days"=>"2", "netto_price"=>"1.0", "_destroy"=>"false", "id"=>"57"}, "1"=>{"from_days"=>"3", "to_days"=>"7", "netto_price"=>"23", "_destroy"=>"false"}, "2"=>{"from_days"=>"9", "to_days"=>"10", "netto_price"=>"123", "_destroy"=>"false"}}
Now i want to check that:
1[:from_days] > 0[:to_days]
2[:from_days] > 1[:to_days]
etc.
Problem is that I want to do it dynamically because in future this parameters will grow up. Did anyone have idea how to solve this problem?
You can try this:
params = {"0"=>{"from_days"=>"1", "to_days"=>"2", "netto_price"=>"1.0", "_destroy"=>"false", "id"=>"57"}, "1"=>{"from_days"=>"3", "to_days"=>"7", "netto_price"=>"23", "_destroy"=>"false"}, "2"=>{"from_days"=>"9", "to_days"=>"10", "netto_price"=>"123", "_destroy"=>"false"}}
(params.keys.min..params.keys.max).each do |index|
if params[(index+1).to_s][:from_days].to_i > params[index.to_s][:to_days].to_i
# your logic when 1[:from_days] > 0[:to_days] is true
else
end
end
This code implies that your params hash :
must contain consecutive keys (no gap between each)
must contain a hash having the [:from_days] AND the [:to_days] keys
Related
Using javascript, I make a fetch post.
const game = {name: this.player, snake: this.snake, score: this.score, apple: this.apple, skull: this.skull, completed: this.completed}
return fetch("http://localhost:3000/games", {
method: "POST",
headers: {
"Content-Type": "application/json"},
body: JSON.stringify(game)
})
.then(resp => resp.json())
.then(json => Game.appendHighScores(json));
I access the data via params on the Ruby on Rails end. The data for params[:snake][:body] are supposed to look like "body"=>[{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}]}, yet when I type them into the command line, they look like this:
[<ActionController::Parameters {"x"=>16, "y"=>15} permitted: false>, <ActionController::Parameters {"x"=>16, "y"=>14} permitted: false>, <ActionController::Parameters {"x"=>16, "y"=>15} permitted: false>]
It is accessible via indexing, but I get everything along with the data I'm looking for.
I was hoping it would look like the original params when I typed it in
<ActionController::Parameters {"name"=>"Don", "snake"=>{"x"=>16, "y"=>15, "direction"=>"down", "speed"=>0, "directions"=>{"left"=>{"x"=>-1, "y"=>0}, "up"=>{"x"=>0, "y"=>-1}, "right"=>{"x"=>1, "y"=>0}, "down"=>{"x"=>0, "y"=>1}}, "image"=>{}, "body"=>[{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}]}, "score"=>0, "apple"=>{"image"=>{}, "x"=>2, "y"=>10}, "skull"=>{"image"=>{}, "x"=>12, "y"=>12}, "completed"=>true, "controller"=>"games", "action"=>"create", "game"=>{"score"=>0, "skull"=>{"image"=>{}, "x"=>12, "y"=>12}, "apple"=>{"image"=>{}, "x"=>2, "y"=>10}, "completed"=>true}} permitted: false>
Anyway to get the params as an array without it looking so messy with ActionController::Parameters inside of the element?
The reason everything is wrapped inside ActionController::Parameters is for your security (mass assignment in particular). You should never trust data send from the internet. This class allows you to permit/whitelist what properties you trust and filter out everything that you don't trust.
snake_params = params.require(:snake).permit(body: [:x, :y])
You can then convert this into a hash with a simple to_h call, which will drill down into all other nested parameters that are also permitted.
snake_data = snake_params.to_h
#=> { "body" => [{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}] }
If you'd like to include other attributes as well you can add them to the permit list.
.permit(:direction, :speed, directions: {left: [:x, :y], up: [:x, :y], ...}, body: [:x, :y])
For more info about permit I suggest checking out the guide Action Controller Overview - 4.5 Strong Parameters.
If you don't care about permitting certain parameters you can permit everything with permit!.
Note that you don't have to permit parameters if you extract the values directly. The code below would work perfectly fine without permitting anything.
body = params[:snake][:body]
body.each |body_part|
x = body_part[:x]
y = body_part[:y]
// do stuff with x and y
end
Because Rails utilize "strong parameters" you have to list and allow the parameters in the controller you want to use.
Since you have a list of parameters with dynamic keys the easiest way to do, while you are in development mode is to permit them like this:
# in your controller
def game_params
params.require(:game).tap do |permitted|
permitted[:name] = params[:name].permit!
permitted[:snake] = params[:snake].permit!
permitted[:apple] = params[:apple].permit!
permitted[:skull] = params[:skull].permit!
permitted[:completed] = params[:completed].permit!
end
end
and then you will be able to access your params:
game_params[:snake][:body]
In production tho, I will encourage you to whitelist all of the keys, for example like this.
The following PATCH action is getting the following parameters
Parameters: {"utf8"=>"✓", [...], "contractgroup"=>
{"articolocontractgroups_attributes"=>
{"0"=>{"articolo_id"=>"0", "id"=>"425"},
"1"=>{"articolo_id"=>"true", "id"=>"426"},
"2"=>{"articolo_id"=>"true", "id"=>"427"},
"3"=>{"articolo_id"=>"0", "id"=>"428"}}, "contractgroup_id"=>"2"}, "commit"=>"Add"}
however the controller action is invoking the parameters in a mistaken manner, as no records are being created:
params[:contractgroup][:articolocontractgroups_attributes].each do |id, attrs|
if params[:articolo_id] == "true"
#articolocontractgroup = Articolocontractgroup.new
(articolo_id: params[:contractgroup][:articolo_id],
contractgroup_id: params[:contractgroup][:contractgroup_id])
#articolocontractgroup.save
end
end
where is this messed up?
You need to check attrs[:articolo_id] == "true" instead params[:articolo_id]
I put in a binding.pry at the top of my controller's update action. Once at that break point, I put in params[:foo_bar] to examine the params hash. Here is what I get:
<ActionController::Parameters {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"123==", "foobar"=><ActionController::Parameters {"barbazz_attributes"=>{"start_date"=>"08/27/2016", "end_date"=>"08/29/2016", "id"=>"89"}, "bazz_id"=>"3", "abc_id"=>"330", "bazzbazz_attributes"=>{"0"=>{"_destroy"=>"1", "city_id"=>"1669", "id"=>"26"}, "1"=>{"city_id"=>"1681", "id"=>"27"}, "2"=>{"city_id"=>"1672"}}} permitted: false>, "cat_id"=>["1", "1", "1"], "commit"=>"Update FooBar", "controller"=>"foo_bars", "action"=>"update", "id"=>"52"} permitted: false>
I assumed permitted: false is there because I did not whitelist some attributes. I looked over the attributes and it appears to me that I did whitelist everything.
I am using Rails 5 if that happens to make any difference.
Question: What is an easy way to find out why the strong parameters are returning params: false.
Don't access params directly with params instead use the name you gave your permitted params, for example: foobar_params.
If foobar_params is defined:
def foobar_params
params.require(:foobar).permit ...
end
The easiest way is to read the source code for ActionController::Parameter, permitted = false is the default unless you call permit! to allow all, but that defeats the purpose of strong parameters.
I have the following hash and I'm looking for an easy way to check if everything is empty in the hash. Not all values are always visible in the hash so sometimes the hash is without end_date / start_date or anything else.
test
=> {"0"=>
{"_destroy"=>"",
"START_DATE"=>"",
"END_DATE"=>"",
"EMPLOYER"=>"",
"JOB_TITEL"=>"",
"FUNCTIONAL_AREA"=>"",
"INDUSTRY"=>"",
"DESCRIPTION_TXT"=>"",
"COUNTRY"=>"",
"CITY"=>"",
"REGION"=>"",
"CONTRACT_TYPE"=>""},
"1"=>
{"_destroy"=>"",
"START_DATE"=>"",
"END_DATE"=>"",
"EMPLOYER"=>"",
"JOB_TITEL"=>"",
"FUNCTIONAL_AREA"=>"",
"INDUSTRY"=>"",
"DESCRIPTION_TXT"=>"",
"COUNTRY"=>"",
"CITY"=>"",
"REGION"=>"",
"CONTRACT_TYPE"=>""},
"2"=>
{"_destroy"=>"",
"START_DATE"=>"",
"END_DATE"=>"",
"EMPLOYER"=>"",
"JOB_TITEL"=>"",
"FUNCTIONAL_AREA"=>"",
"INDUSTRY"=>"",
"DESCRIPTION_TXT"=>"",
"COUNTRY"=>"",
"CITY"=>"",
"REGION"=>"",
"CONTRACT_TYPE"=>""}}
In pseudocode it would like this
Start loop
-> check if current position contains an empties
=> if all is empty delete position
-> continue
end loop
In this example it means that the hash will be empty at the end of the loop.
Kind regards
Use Hash#delete_if:
test.delete_if { |i,h| h.all? { |k,v| v.empty? } }
I have a hash of hashes like so:
Parameters: {"order"=>{"items_attributes"=>{"0"=>{"product_name"=>"FOOBAR"}}}}
Given that the depth and names of the keys may change, I need to be able to extract the value of 'product_name' (in this example "FOOBAR") with some sort of search or select method, but I cannot seem to figure it out.
An added complication is that Params is (I think) a HashWithIndifferentAccess
Thanks for your help.
Is this what you mean?
if params.has_key?("order") and params["order"].has_key?("items_attributes") then
o = params["order"]["items_attributes"]
o.each do |k, v|
# k is the key of this inner hash, ie "0" in your example
if v.has_key?("product_name") then
# Obviously you'll want to stuff this in an array or something, not print it
print v["product_name"]
end
end
end