Check if hash contains any empty values - ruby-on-rails

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? } }

Related

Rails: reshape params to desired structure

I have some params that I need to reshape?
I've got an old database I'm trying to build a new app on top of to access and do CRUD operations on.
I simply need to make this structure...
{
"volunteer_shift_attributes"=><ActionController::Parameters{
"volunteer_task_type_id"=>"41",
"roster_id"=>"7",
"program_id"=>"9",
"set_description"=>"ddddddddddd"
} permitted: true>,
"set_date"=>"2021-01-14",
"contact_id"=>"166574",
"closed"=>"0",
"start_time(4i)"=>"14",
"start_time(5i)"=>"00",
"end_time(4i)"=>"15",
"end_time(5i)"=>"00",
"notes"=>"nnnnnnnnnnnnn",
}
have this structure...
{
"volunteer_shift_attributes"=>{
"volunteer_task_type_id"=>"41",
"roster_id"=>"7",
"program_id"=>"9",
"set_description"=>"ddddddddddd"
},
"set_date"=>"2021-01-15",
"contact_id"=>"166574",
"closed"=>"0",
"start_time(4i)"=>"14",
"start_time(5i)"=>"00",
"end_time(4i)"=>"15",
"end_time(5i)"=>"00",
"notes"=>"aaaaaaaaaaaaaa"
}
NOTE: this is called inside a controller method like so
def create_shift
...
a.attributes = (params["assignment"])
...
end
I need to rebuild this param by hand.
It's not clear exactly why you need to do this - they're just params and you're not looking to change the structure, exactly. But it looks like it could be a case for strong params. Define a private method:
def volunteer_shift_params
params.require(:volunteer_shift_attributes)
.permit(:volunteer_task_type_id,
:roster_id,
:program_id,
:set_description)
end
Then, you should be able to do this, as you asked:
a.attributes = volunteer_shift_params

How can I access the data for the snake object sent through JSON in my params?

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.

create records only when boxes checked

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]

Comparing hash values

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

No method Error Undefined method for stringify_keys for array for my time-sheet controller

Here, a user submits a timesheet for some time period by selecting start-date and end-date. Those params are assigned to timesheet_params then it is passed to the timesheet model.
I am getting this error when building timesheets for particular days:
Started GET
"/users/2/timesheets/build?start_date=06/08/2013&end_date=06/11/2013"
for 127.0.0.1 at Tue Jun 11 23:24:23 +0530 2013 Processing by
TimesheetsController#build as / Parameters:
{"end_date"=>"06/11/2013", "start_date"=>"06/08/2013", "user_id"=>"2"}
[1m[36mUser Load (0.1ms)[0m [1mSELECT users.* FROM users WHERE
users.id = 2 LIMIT 1[0m Completed 500 Internal Server Error in 3ms
NoMethodError (undefined method stringify_keys' for
#<Array:0xb23ed8f4>):app/controllers/timesheets_controller.rb:23:innew' app/controllers/timesheets_controller.rb:23:in `build'
The code I am using is:
// time sheet build method //
def build
#user = current_user
timesheet_params = params.select{|k,v| ["start_date", "end_date", "user_id"].include?(k) }
#timesheet = Timesheet.new(timesheet_params)
#timesheet.placement = #user.active_assignment
if #timesheet.valid?
if #timesheet.timesheet_days.blank?
build_timesheet_days
end
else
render :status => 500 and return
end
end
I'm going to guess that you're using Ruby 1.8 where Hash#select returns an Array:
select {|key, value| block} => array
Returns a new array consisting of [key,value] pairs for which the block returns true.
That would mean that your timesheet_params is actually an Array. Then you hand that Array to ActiveRecord:
Timesheet.new(timesheet_params)
and AR will try to convert the what-it-expects-to-be-a-Hash keys to strings using the stringify_keys method that Rails patches into Hash and everything falls apart because timesheet_params is actually an Array. That at least matches the behavior you're seeing.
The solution is to not use params.select at all, just use the slice method that Rails adds to Hash:
timesheet_params = params.slice("start_date", "end_date", "user_id")
The Hash#select method in newer versions of Ruby return a Hash. Also 1.8 is quite ancient so you should upgrade ASAP if possible.
For the pedants: Yes, params is actually an ActiveSupport::HashWithIndifferentAccess but that subclasses Hash and is rarely an important distinction.

Resources