Ruby or Ruby on Rails group_by on dynamically changing parameters - ruby-on-rails

I want to change group_by parameters based on user input.
Example:
Data on which i am going to group:
result = [{"result_1"=>"01","result_2"=>"August","result_3"=>"2016","result_4"=>264},{"result_1"=>"02","result_2"=>"August","result_3"=>"2016","result_4"=>49},{"result_1"=>"03","result_2"=>"August","result_3"=>"2016","result_4"=>53}]
I know how a ruby group_by works with multiple parameters.
To group_by on result_1 and result_2.It can be done this way:
result.group_by{|h| [h["result_1"],h["result_2"]}
Above code groups the data based on result_1 and result_2.Here the parameters are hard_coded.
I want group_by based on parameters passed dynamically.As
dynamic_parameter = ["result_3","result_4"]
I want group_by to be as
result.group_by{|h| [h["result_3"],h["result_4"]]}
i want to do it as roughly:
dynamic_parameters.each do |parameter|
result.group_by{|h| [h[parameters]}
end
or similar to:
result.group_by{|h| [h[parameters[0]],h[parameters[1]]}
These result_3 and result_4 parameters are based on dynamic_parameter array values.
Note: Group_by should vary based on the array elements.

If I understood your question correctly then something like this would do the job:
result.group_by do |h|
dynamic_parameters.map{ |p| h[p] }
end
Or one-liner:
result.group_by { |h| h.values_at(*dynamic_parameters) }

Related

rails controller invoking params of nested attributes

Submitting the following parameters
Parameters: {[...] "physicalinventario"=>{[...] "physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>",85"}}}, "commit"
The goal is to intercept the quantity parameter at the physicalinventarioitem controller create action, and sanitize it for possible comma as decimal value being input
if params[:physicalinventario][:physicalinventarioitems_attributes][:quantity].include? ","
params[:physicalinventarioitem][:quantity] = params[:physicalinventario][:physicalinventarioitems_attributes][:quantity].tr!(',', '.').to_d
end
However, the syntax is wrong as no value after the comma is being handled.
#Alex answer is fine if you have only one quantity.
but what if you have multiple quantites,
eg: {"0"=>{"quantity"=>",85"},"1"=>{"quantity"=>",90"}}
So, here is the answer which also achieves that requirement for multiple nested attributes.
hash = {"physicalinventario"=>{"physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>",85"},"1"=>{"quantity"=>",90"}}}}
The code that you require,
hash["physicalinventario"]["physicalinventarioitems_attributes"].each do |key, value|
if value["quantity"].include? ","
value["quantity"] = value["quantity"].tr!(',', '.').to_f
end
end
Here is the resultant hash,
`{"physicalinventario"=>{"physicalinventarioitems_attributes"=>{"0"=>{"quantity"=>0.85}, "1"=>{"quantity"=>0.9}}}}`
Looks like you've missed ["0"] in the chain to get :quantity.
Should be
params[:physicalinventario][:physicalinventarioitems_attribu‌tes]["0"][:quantity]
Most convenient Rails way to sanitize(normalize) data in a model.
To don't create duplicates, more here How best to sanitize fields in ruby on rails

Nice array from pluck

I have a model and I love the pluck method I can use. If I do this:
#x = AwesomeModel.all.pluck(:column_one, :column_two)
then I get a multidimensional array: #x[][]. With my sad skills, I work with them using the numbers:
#x[0][1]
how can I can use pluck or a similar method to access the array something like this:
#x[0][:column_two]
If you are concerned about the structure of what you get back from the db, you should simply do:
#x = AwesomeModel.all.select(:column_one, :column_two)
Then you'd keep the fast db query advantage + have AwesomeModel instances, but with only column_one and column_two filled
Or if you desire to do it manually:
#x = AwesomeModel.all.pluck(:column_one, :column_two).map do |array|
OpenStruct.new({column_one: array[0], column_two: array[1] }) }
end
Then you can use it like a regular model:
#x[0].column_one
# or even
#x[0][:column_two]
You could do
class ActiveRecord::Base
def self.pluck_hash(*args)
plucked = pluck(*args)
plucked.map {|ary| Hash[args.zip ary]}
end
end
AwesomeModel.all.pluck_hash(:column_one, :column_two)
#=> [{:column_one => 'value', :column_two => 'value}, {...}, ... ]
First of all, don't use .all.pluck, because it returns an array of values, and that makes you loose all the advantages of ActiveRecord::Relation.
Instead use AwsomeModel.method directly, it would create the query but not run it until you need it, AwsomeModel.select(:column_1, :column_2) would create a
select (awesome_models.column_1, awsome_models.column_2)
query, and the result would be an array of ActiveRecord::Relation objects, which are still chainable, and values are still under keys of the column name eg:
AwsomeModel.select(:column_1, :column_2).first.column_1
Instead of
AwesomeModel.all.pluck(:column_1, :column_2).first[0] # or .first.first

Set first group of group_by?

Good day, I was wondering, is it possible if i make a selection with group_by like so
#p = Performance.includes(place: [:category]).
order("places.title ASC").
group_by{|p| p.place.category}
so if i want a specific category to be the first, what do i do?
EDIT 1
in view a parse through the results by #p.each do |p|
The return value of group_by is just a normal hash, so you can apply sort_by on it to place your desired category first:
group_by { |p| p.place.category }.sort_by { |k,v| (k=="category name") ? "" : k }
where category name is the name of the category you want to prioritize (the empty string make it come first in the sort results, everything else will just be sorted alphabetically).
This will transform the hash into an array. If you want to keep the data in hash form, wrap the result in Hash[...]:
Hash[group_by { |p| p.place.category }.sort_by { |k,v| (k=="category name") ? "" : k }]
See also this article on sorting hashes: http://www.rubyinside.com/how-to/ruby-sort-hash
UPDATE:
A slightly less processor-intensive alternative to sorting:
grouped = group_by { |p| p.place.category }
Hash[*grouped.assoc("category name")].merge(grouped.except("category name"))
There might be a simpler way to do this, but basically this prepends the key and value for "category name" to the head of the hash.
Although I think shioyama's answer might help you, I doubt you really need the sort process. As shio correctly states, the return value of your sort_by is a hash. So why dont you just access the value, which you want as the first value, simply by using it as hash-key?

How to create a grouped select from a flat hash of values?

I am pulling a flat hash of parameters from an external API into my Rails app. I need to present these parameters to the user in a select field.
The hash is formatted as follows:
[["Name", "ID", "Category"]]
I'd like to present this as a grouped select. But I believe the grouped_select tag takes a hierarchical hash, not a flat hash?
Is there an easy way to restructure this hash into a structured hash? i.e.,
['CategoryA', [['Name-A1','ID-A1'],['Name-A2', 'ID-A2']]
For reference, I'm currently handling the hash in my controller like this
#hash = session["hash"].map { |h| [ h["name"], h["id"], h["category"] ] }
and in the view
<%= f.select :hash_id, #hash %>
This gives me an unordered list of options. How can I group on h["category"]?
Thanks for any pointers.
EDIT
By the way, I;ve already tried group_by as it seemed the obvious way to go. But I'm getting can't convert String into Integer. Perhaps I'm not using it correctly?
hash.group_by {|h| h["category"] }.map { |h| [ h["name"], h["id"], h["category"] ] }
hash.group_by {|h| h["category"] }.map { |h| [ h[0], h[1].map{|e| [e["name"],e["id"]]} ] }

Searching in a subhash with Ruby on Rails

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

Resources