create a hash in an array with values from database - ruby-on-rails

i have firstname,lastname and id of a list of people in database.
Now i want to make an array like
[{
value: <corresponding id>,
label: "<corresponding person name>"
},
{
value: <corresponding id>,
label: "<corresponding person name>"
},
....
]

users = User.all
user_hash_array = users.collect{|user| {:value => user.id, :label => user.firstname}}
This will work like following
id firstname lastname
1 Salil Gaikwad
2 Nidhin Bose
This will gives you following
user_hash_array = [{:value=>1, :label=>"Salil"}, {:value=>2, :label=>"Nidhin"}]

Related

Ruby how to format nested hash

I have two queries I am running and iterating over both and my final hash is seen below. But, I want to have format on how the data is being stored in the hash that I'm creating or format it after I'm done creating it. But I am not sure how to achieve the desired format where the names fall under the same id as show below
desired format of example data:
[
{
id: 1,
accepted: false,
trans: 10234
names: [
{ name: "Joe", amount: "$1,698.00" },
{ name: "Smith", amount: "$674.24" },
]
},
{
id: 2,
accepted: true,
trans: 10234,
names: [
{ name: "Joe", amount: "$1,698.00" },
{ name: "Smith", amount: "$674.24" },
]
}
]
current format I have
[
{
:id => 1,
:accepted => false,
:trans => 8,
:name => "Smith",
:amount => 36.0
},
{
:id => 1,
:amount => false,
:trans => 8,
:name => "Joe",
:amount => 6.0
},
{
:id => 3,
:accepted => false,
:trans => 8,
:name => "Tom",
:amount => 34.0
},
{
:id => 3,
:accepted => false,
:trans=> 8,
:name => "Martha",
:amount => 4.0
}
],
[
{
:id => 2,
:accepted => true,
:trans => 7,
:name => "Bob",
:amount => 35.0
},
{
:id => 2,
:accepted => true,
:trans => 7,
:name => "John",
:amount => 5.0
}
]
logic for creating hash
imports = ListImports.limit(20).order(created_at: :DESC)
groups = imports.map{|import| ListImportGroup.where(list_import_id: import.id)}
pub_hash_true = []
pub_hash_false = []
hash = []
imports.map do |import|
hash << {
id: import.id,
trans: import.trans,
accepted: import.amount
}
end
hash.each do |import|
groups.flatten.each do |group|
accepted = import[:accepted]
num_transactions = import[:trans]
if accepted == false
pub_hash_false << {id: import[:id], accepted: accepted, trans: num_transactions, name: group.name, amount: group.amount}
else
pub_hash_true << {id: import[:id], accepted: accepted, trans: num_transactions, name: group.name, amount: group.amount}
end
end
end
# Note: You didn't specify what is the association between `ListImport` and `ListImportGroup`.
# However, I'm fairly sure you could be fetching this data via a JOIN query like below,
# rather than making up to 20 additional database calls to fetch the associated records.
imports = ListImports.limit(20).order(created_at: :DESC).includes(:list_import_group)
result = imports.map do |import|
{
id: import.id,
trans: import.trans,
accepted: import.amount,
names: import.list_import_groups.pluck(:name, :amount)
}
end
And if you do actually need to filter for imports where accepted is true or false, you could do something like this instead of building separate arrays manually:
accepted_imports = result.select { |import| import[:accepted] }
# and
rejected_imports = result.reject { |import| import[:accepted] }
# or even:
accepted_imports, rejected_imports = result.partition { |import| import[:accepted] }
You didn't specify the exact correspondence between the desired and current formats.
But I assume
For the entries with the same id, the values of accepted and trans are identical.
the desired amount for Joe in the current format is identical in the corresponding amount in the desired amount. (In your example, the former is 6.0 whereas the latter is "$1,698.00", which does not make sense.)
Then, the following would do the conversion. The array ahout is in the desired format.
# Let us assume "a1" is the original array in the "current format"
hout = {}
a1.flatten.map{|h|
h.slice(*(%i(id trans name amount accepted))).values
}.each{ |a|
hout[a[0]] = {id: a[0], accepted: a[4], trans: a[1], names: []} if !hout.key? a[0]
hout[a[0]][:names].push(
{name: a[2], amount: "$"+helper.number_with_precision(a[3], precision: 2, delimiter: ',')}
)
}
ahout = hout.values
You may want to sort ahout, if you like.
Note that I am assuming you are using Rails 5+. Otherwise, the method helper may not work. In that case, you can use sprintf or whatever formatting method.

RUBY - Correct way of doing array of hashes inside of hash

i need to do an array of hashes inside of a hash, something like this:
merit_hash => {
students => [
{
"id": id,
"name": name,
subjects => [
{
"id": id,
"grade": grade
},
{
"id": id,
"grade": grade
}
]
},
{
"id": id,
"name": name,
subjects => [
{
"id": id,
"grade": grade
},
{
"id": id,
"grade": grade
}
]
}
]
}
Right now, i just have the array of student hashes, but i dont exactly know how to put the subject array inside of it, im doing this:
merit = {}
merit["students"] = []
students.each do |students|
student_subjects = Array.new
merit["students"].push(
{
"id" => students.id,
"name" => students.name.to_s
selected_batch_subjects.each do |subjects|
grade = FinalGrades.where(batch_subject_id:subjects.id, period_id: period.id, student_id: student.id).first.value
student_subjects.push(
{
"id" => subjects.id,
"grade"=> grade
}
)
end
}
)
end
but throws this error
unexpected '}', expecting keyword_end
when i try to close the student hash... what can i do to make this work? or, whats the best way of implementing this?
Thanks!
Something like this should work:
merit = {}
merit["students"] = []
students.each do |student|
student_information = {"id" => student.id, "name" => student.name.to_s}
student_subjects = []
selected_batch_subjects.each do |subjects|
grade = FinalGrades.where(batch_subject_id:subjects.id, period_id: period.id, student_id: student.id).first.value
student_subjects.push({"id" => subjects.id, "grade" => grade})
end
student_information[:subjects] = student_subjects
merit["students"].push(student_information)
end
The important part is adding each student's subjects to the already existing hash.
Your iterations are not very clear to me but for current loop and array push you could do like this:
merit = {}
merit["students"] = []
students.each do |students|
student_subjects = []
merit["students"] << {
"id" => students.id,
"name" => students.name.to_s
}
selected_batch_subjects.each do |subjects|
grade = FinalGrades.where(batch_subject_id:subjects.id, period_id: period.id, student_id: student.id).first.value
student_subjects << {"id" => subjects.id,"grade"=> grade}
end
end

Get other field if this is included in the array object

Title may sound off but below explains more.
I need to know if an item is included in an array object:
[
{ id: 12345, name: "Bob", email: "bob#builder.com" },
...
{ id: 13456, name: "job", email: "joe#farm.com" }
]
In english: If this email present, give me their id
users = User.all
users.any?{|u| u.email == "bob#builder.com"} # true
That will be true. Now, how to get the id of the user which is "12345"? Note, I will not know the id.
Since you seem to be using ActiveRecord, it would be faster to query the database for the email:
# returns the user id or nil, if not found
User.find_by(email: 'bob#builder.com').pluck(:id)
You can try like this if you have array of hashes:
arr.map do |h|
h[:id] if h[:email] == "bob#builder.com"
end.compact
It will return the value of id in an array of all the hashes which satisfies the condition.

create a specific hash (dynamic)

How I can create a hash like this in a cycle ?
User.items.each do |m|
......
Result:
test = [{:name => 'Unit 1', :price => "10.00"},
{:name => 'Unit 2', :price => "12.00"},
{:name => 'Unit 3', :price => "14.00"}]]
You can use map to return hashes that you build.
Assuming your Item resource responds to name and price, it would look like
test = User.items.map do |m|
{
name: m.name,
price: m.price
}
end
You also can do like this:
Item.connection.select_all("select name, price from items where user_id = xxxxx;")
you will get an array containing hash, like this:
[{"name"=>"xxx", "price"=> xxx},{}......]

Rails Creating a Valid JSON object

I could use your helping creating a valid JSON object in Rails.
Here is an example of a valid JSON object that I'm using in the jQuery plugin: https://drew.tenderapp.com/kb/autosuggest-jquery-plugin
var data = {items: [
{value: "21", name: "Mick Jagger"},
{value: "43", name: "Johnny Storm"},
{value: "46", name: "Richard Hatch"},
{value: "54", name: "Kelly Slater"},
{value: "55", name: "Rudy Hamilton"},
{value: "79", name: "Michael Jordan"}]};
Within Rails I'm creating my object as follows:
#projects = Projects.all
#projectlist = Array.new
#projectlist << {
:items => #projects.map { |project|
{
:name => space.name,
:value => space.id
}
}
}
But this ends up outputting like so which ERRORs by the plugin:
[{"items":[{"value":74,"name":"XXXXXX"},{"value":71,"name":"XXXXXX"},{"value":70,"name":"XXXXXX"}]}]
Looks like there is a [] around the initial {} any idea why that's happening and how to build a valid JSON object?
Thanks!
Simply assign #projectlist to a Hash, like so:
EDIT After looking at the plugin's API, I've come to the conclusion that you need to convert your values to strings first:
#projects = Projects.all
#projectlist = {
:items => #projects.map { |project|
{
:name => space.name,
:value => space.id.to_s
}
}
}
Since you're initializing #projectlist to an Array and pushing the Hash onto it, you're getting those wrapping [] characters.

Resources