I am using a hash constant in my ROR application. I want to show the names from the hash constant to drop down.
helper.rb
PRODUCE_GROWING_METHODS = [
{id: 1, name: 'Conventional'},
{id: 2, name: 'Organic'},
]
def produce_growing_methods
PRODUCE_GROWING_METHODS
end
_produce.haml
= f.simple_fields_for :produce_details do |pd|
= pd.input :produce_growing_method, :collection => produce_growing_methods.collect { |x| [x[0], x[1]] }, :prompt => "Select Growing Method"
I tried as shown above in _produce.haml but i am getting the empty drop down. Names from the constant are not populated in drop down.
Can any one help me how to show the names from the PRODUCE_GROWING_METHODS hash constant to a drop down.
Thanks
You should map the hash by keys. In your case the keys are :id and :name:
produce_growing_methods.map { |x| [x[:id], x[:name]] }
In reality you are always better of using a generic solution rather then manual mapping.
Here is a better way of achieving the same, but it will work as well for array of thousand hashes:
ary = [
{id: 1, name: 'Conventional'},
{id: 2, name: 'Organic'},
]
ary.map(&:values)
#=> [[1, "Conventional"], [2, "Organic"]]
Related
I used group_by to get a certain desired result. Based on the explanation in the answer, I have updated my question to reflect the answer, to see the steps it took to arrive at a solution, see the edit history.
#grouped_test_specific_reports = TestSpecificReport.all.group_by(&:equipment_type_name)
The code above produced this result:
2.5.1 :026 > pp #grouped_test_specific_reports
{"Ultrasonic Probes"=>
[#<TestSpecificReport:0x00007f832aa2d6e0
id: 10,
equipment_type_id: 2,
test_method_id: 1,
equipment_amount: "Multiple",
equipment_heading: "UT Probes">],
"Ultrasonic Instruments"=>
[#<TestSpecificReport:0x00007f832aa2d3c0
id: 8,
equipment_type_id: 1,
test_method_id: 1,
equipment_amount: "Single",
equipment_heading: "UT Instrument">],
"Visual Test Equipment"=>
[#<TestSpecificReport:0x00007f832aa2cfb0
id: 11,
equipment_type_id: 4,
test_method_id: 1,
equipment_amount: "Single",
equipment_heading: "VT Equipment">]}
=> {"Ultrasonic Probes"=>[#<TestSpecificReport id: 10, equipment_type_id: 2, test_method_id: 1, equipment_amount: "Multiple", equipment_heading: "UT Probes">], "Ultrasonic Instruments"=>[#<TestSpecificReport id: 8, equipment_type_id: 1, test_method_id: 1, equipment_amount: "Single", equipment_heading: "UT Instrument">], "Visual Test Equipment"=>[#<TestSpecificReport id: 11, equipment_type_id: 4, test_method_id: 1, equipment_amount: "Single", equipment_heading: "VT Equipment">]}
My next goal is to list out the grouped test specific report in the browser by their keys, I was able to do that by #grouped_test_specific_reports.each { |key, value| puts key }
"Visual Test Equipment"
"Ultrasonic Instruments" and
"Ultrasonic Probes"
Now we have to iterate over the values, which happens to be an array, in another loop to be able to compare equipment_amount.
The values with equipment_amount: "Multiple" will have the plus icon in front of them, and the ones with equipment_amount: "Single" will simply be a drop-down:
Here's the code for the UI:
- #grouped_test_specific_reports.each do |equipment_type_name, test_specific_reports|
.form-group.row
.col-sm-6
%label
= equipment_type_name
= select_tag '', options_from_collection_for_select(test_specific_reports, :id, :equipment_heading), { include_blank: "Select #{equipment_type_name} List", class: 'form-control select2', style: 'width: 100%;' }
.col-sm-1
- test_specific_reports.each do |test_specific_report|
- if test_specific_report.equipment_amount == 'Multiple'
.icon.text-center
%i.fa.fa-plus-circle.add-icon
I personally found the question you're asking a bit unclear. For this reason I discussed some things in the comments with you. From our discussion in the comments it seemed you simply wanted to loop through the grouped values for each group.
First I want to clear up what group_by exactly does, because this seemed to be the issue. A simple misunderstanding of what you're currently working on.
group_by { |obj| block } → a_hash
group_by → an_enumerator
Groups the collection by result of the block. Returns a hash where the keys are the evaluated result from the block and the values are arrays of elements in the collection that correspond to the key.
If no block is given an enumerator is returned.
(1..6).group_by { |i| i%3 } #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
The documentation makes clear that the grouped hash has keys that evaluate from the block (the return value). The value that belongs to the key is actually an list of values that evaluate to the same result. This means you can simply loop through the values in the following way.
grouped_values = (1..6).group_by { |n| n % 3 }
grouped_values.each do |key, values|
puts "Key: #{key}"
values.each do |value|
puts "Value: #{value}"
end
end
The first each loops through the groups. The second each loops through the values of the group. Since you loop though two different things you can't change this into a single loop easily. The important thing to remember here that the value belonging to a group key is not a single value, but rather a group of values (array).
This question already has answers here:
How to get a specific output iterating a hash in Ruby?
(6 answers)
Closed 6 years ago.
I want to iterate over this data to extract the value of the ids:
[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ]
You can use Array's map method like below:
arr =[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ]
ids = arr.map { |k| k[:id] }
#=> [3,4]
[ {:id => 3, :quantity => 5 }, { :id => 4, :quantity => 3 } ].each do |hash|
puts hash[:id]
end
This will puts each id value on the screen. You can do what you need to do from there.
Ruby: Mapping Over an Array with Hash#values_at
There's more than one way to do this in Ruby. A lot depends on what you're trying to express. If you're not trying to play code golf, one way to do this is with Hash#values_at. For example:
[{id: 3, quantity: 5}, {id: 4, quantity: 3}].flat_map { |h| h.values_at :id }
#=> [3, 4]
Rails: Extracting Data with Pluck
A more Rails-like way would be to just ActiveRecord::Calculations#pluck the attributes you want in the query itself. For example:
Stuff.where(quantity: [3, 5]).pluck :id
There are certainly other ways to get the same result. Your mileage may vary, depending on your real use case.
See Also
Active Record Query Interface
In Ruby on Rails 4, I'm trying to make an API for my website and instead of using an array like so:
[{id: 1, name: "John"}, {id: 2, name: "Foo"}, {id: 3, name: "Bar"}]
I want to render it like this, because it makes it much easier to search through in javascript (and for other reasons):
{"1": {id: 1, name: "John"}, "2": {id: 2, name: "Foo"}, "3": {id: 3, name: "Bar"}}
This works:
# users/index.rabl
#users.each do |user|
node(users.id.to_s) do
partial('api/v1/users/show', object: user)
end
end
But in the partial, I want another collection of elements (which belong to the user) and I can't get that working. Is there a more elegant way to do this?
To choose hash-map rather than array is definitely better option if have control on API backend codebase. From BigO notation hash lookup happens with constant O(1) time, not O(n) as for array.
Primary key lookup from the database is the most performant way to query data. Primary key is usually short and always indexed. In case of big data set use pagination.
Let's assume there is no RABL (you can always instantiate pure Ruby classes in RABL DSL code) but just an array:
array = [{id: 1, name: "John"}, {id: 2, name: "Foo"}, {id: 3, name: "Bar"}]
hash = {}
array.each{ |elem,i| hash[elem[:id].to_s] = elem }
# {"1"=>{:id=>1, :name=>"John"}, "2"=>{:id=>2, :name=>"Foo"}, "3"=>{:id=>3, :name=>"Bar"}}
To pass the Ruby hash to Javascript on client you probably want to encode it appropriately:
# hash.to_json
# {"1":{"id":1,"name":"John"},"2":{"id":2,"name":"Foo"},"3":{"id":3,"name":"Bar"}}
From Javascript you query hash by its key:
hash = {"1":{"id":1,"name":"John"},"2":{"id":2,"name":"Foo"},"3":{"id":3,"name":"Bar"}}
hash[1]
# Object { id=1, name="John"}
I am looking for the Ruby/Rails way to approach the classic "select items from a set based on matches with another set" task.
Set one is a simple hash, like this:
fruits = {:apples => "red", :oranges => "orange", :mangoes => "yellow", :limes => "green"}
Set two is an array, like this:
breakfast_fruits = [:apples, :oranges]
The desired outcome is a hash containing the fruits that are listed in Breakfast_fruits:
menu = {:apples => "red", :oranges => "orange"}
I've got a basic nested loop going, but am stuck on basic comparison syntax:
menu = {}
breakfast_fruits.each do |brekky|
fruits.each do |fruit|
//if fruit has the same key as brekky put it in menu
end
end
I'd also love to know if there is a better way to do this in Ruby than nested iterators.
You can use Hash#keep_if:
fruits.keep_if { |key| breakfast_fruits.include? key }
# => {:apples=>"red", :oranges=>"orange"}
This will modify fruits itself. If you don't want that, a little modification of your code works:
menu = {}
breakfast_fruits.each do |brekky|
menu[brekky] = fruits[brekky] if breakfast_fruits.include? brekky
end
ActiveSupport (which comes with Rails) adds Hash#slice:
slice(*keys)
Slice a hash to include only the given keys. Returns a hash containing the given keys.
So you can say things like:
h = { :a => 'a', :b => 'b', :c => 'c' }.slice(:a, :c, :d)
# { :a => 'a', :c => 'c' }
In your case, you'd splat the array:
menu = fruits.slice(*breakfast_fruits)
I'm passing as array of JSON object as a param in Rails through an AJAX post/delete, like
[{'id': 3, 'status': true}, {'id': 1, 'status': true}]
How do I loop through the params[:list] to get each id and status value?
Do this:
params[:list].each do |hash|
hash['id'] # => 3
hash['status'] # => true
end
Try like follows:
params[ :list ][ 0 ][ :id ] # => 3, ...
params[ :list ].each {| v | v[ :id ] } # => 3, 1
In case if your hash is like ["0", {"id"=>"9", "status"=>"true"}]:
# a = ["0", {"id"=>"9", "status"=>"true"}]
h = Hash[[a]]
# => {"0"=>{"id"=>"9", "status"=>"true"}}
and access to it will be:
h['0'][ :id ] # => '9'
There were two steps to this, plus what #Agis suggested. (Thanks #Agis)
I had to first stringify the JSON:
'p': JSON.stringify(p),
So that it does not create that wierd array. There was another stackoverflow answer using this method to generate a correct data JSON object, but it was encapsulating the whole data... I need to have this on just p and not affect 'stringifying' the security token.
Understood this from here: Rails not decoding JSON from jQuery correctly (array becoming a hash with integer keys)
Next, I had to decode just that param, using
ActiveSupport::JSON.decode(params[:p])
a clue from here: How do I parse JSON with Ruby on Rails?
Lastly, can I then use the loop and access item['id']
Here's a loop:
params[:list].each do |item|
item.id
item.satus
end
If you want to create an array of id's or something:
list_ids = params[:list].map(&:id)