How to iterate through an array of hashes in ruby - ruby-on-rails

Trying to iterate over an array using ruby and it is miserably failing,
My Array
people = [{first_name: "Gary", job_title: "car enthusiast", salary: "14000" },
{first_name: "Claire", job_title: "developer", salary: "15000"},
{first_name: "Clem", job_title: "developer", salary: "12000"}]
How to iterate over the above hash to output only the salary value???
I tried using:
people.each do |i,j,k|
puts "#{i}"
end
The results are as below and is not what i was intending,
{:first_name=>"Gary", :job_title=>"car enthusiast", :salary=>"14000"}
{:first_name=>"Claire", :job_title=>"developer", :salary=>"15000"}
{:first_name=>"Clem", :job_title=>"developer", :salary=>"12000"}
Is there a way to iterate through this array and simply list out only the salary values and not the rest?

In newer versions of Ruby (not sure when it was introduced, probably around ruby 2.0-ish which is when I believe keyword arguments were introduced), you can do:
people.each do |salary:,**|
puts salary
end
where ** takes all the keyword arguments that you don't name and swallows them (ie, the first_name and job_title keys in the hash). If that isn't something that your ruby version allows, you'll need to just store the entire hash in the variable:
people.each do |person|
puts person[:salary]
end

Related

rails: how can we add multiple valued params in db in one query in rails?

Consider I have these attributes in table: answers, user_id, question_id
This is what I did:
I stored it with the loop but that's bad practice to trigger database again and again:
temp= params.fetch(:user_answer)
temp["answers"].length.times { |i|
UserAnswer.create!(answers: temp["answers"][i], question_id: temp["question_id"][i], student_id: current_user.id)
}
I have values in my params like this:
"user_answer"=>{"answers"=>["C++ is mother of all the languages", "25"], "question_id"=>["7", "10"], "student_id"=>["12", "12"]}
How can I add multiple records in one query with this params?
You can pass to create array of arguments
But firstly you need to create such array
user_answer_args =
params[:user_answer].each_with_object([]) do |(param, values), args|
values.each_with_index do |value, index|
args[index] ||= {}
args[index].merge!(param => value)
end
end
And than
UserAnswer.create(user_answer_args)
Note: you need to convert params to hash firstly, something like this
user_answer_params =
params.
require(:user_answer).
permit(answers: [], question_id: [], student_id: []).
to_h

Ruby on rails array - no implicit conversion of symbol into integer

I made a table component using react js, which uses columns to display data (which works fine with other data). For example, column 1 would show the title, column 2 the year, and column 3 the format.
Here is an example of my JSON:
{"movies": [{"title": "Iron Man", "year": "2008", "format": "DVD"}, {"title": "Iron Man 2", "year": "2010", "format": "DVD"}, {"title": "Iron Man 3", "year": "2013", "format": "DVD"}]}
Here is my code to populate the table, but it does not seem to work:
#movieList = #Makes a call to my mock API to get list of movies
#movies = Array.new
#movieList.each do |item|
#movie = Hash.new
#movie[:column1] = item[:title]
#movie[:column2] = item[:year]
#movie[:column3] = item[:format]
#movies << #movie
end
I need some advice to overcome a "no implicit conversion of symbol into integer error" I get. Could anyone offer some advice and point out where I am going wrong?
tl;dr
use #movieList["movies"].each
explanation
The issue here, is that you act as though your #movieList is ann array, when it is actually a hash (assuming #movieList is the JSON you showed).
each works on both arrays and hashes. However, when you use it on a hash, the block is passed |key, val|. Also, assigning block variables is optional. So, when you say #movieList.each do |item|, item is actually the top level key of the hash ("movies").
Strings such as "movies" respond to [] indexing with numbers. That's why you get the error no implicit conversion of symbol into integer ... because you pass a symbol to String#[] and it expects an integer.
Another way to write this code, that is more idiomatic, would be like so:
#movies = #movieList["movies"].map do |movie|
{
column1: movie["title"],
column2: movie["year"],
column3: movie["format"]
}
end
try reassigning
#movieList = #movieList[:movies] this will solve your problem. You're trying to iterate a object instead of an array.
lemme know if it solves your problem.
You need to loop movies using #movieList["movies"] as your JSON is a hash that has a key 'movies' and an array of movies as a value => {'movies': [{...},{...},...]}
As #max pleaner explained assigning block variables is optional, but when you use each on a hash(your JSON in this case) and provide only one block variable (instead of two refering to the keys and values of the hash), your key-value pairs are converted to two-element arrays inside the block where first element is the key and second one is the value of the pair.
Your item looks like this inside your each block -
['movies', [{movie1}, {movie2},..]], hence:
item[0] # 'movies'
item[1] # [{movie1}, {movie2},...]
As arrays expect indexing with integers and you supply symbol (item[:title]), you receive:
TypeError (no implicit conversion of Symbol into Integer)

Ruby on Rails Tutorial: Defining a hash with symbol keys

Regarding the exercises in Michael Hartl's RoR Tutorial in lesson 4.3.3 (Hashes & Symbols):
"Define a hash with symbol keys corresponding to name, email, and a “password digest”, and values equal to your name, your email address, and a random string of 16 lower-case letters."
I am hoping to get some input and/or alternative & 'better' solutions to this (or at least some criticism regarding my solution).
def my_hash
a = ('a'..'z').to_a.shuffle[0..15].join
b = { name: "John", email: "johndoe#gmail.com", password: a }
return b
end
puts my_hash
(Yes I realize this is a very simple exercise and apologize if it has been asked before.)
There are many 2 improvements could be made:
Use Array#sample to get random letters (it has an advantage: the letter might in fact repeat in the password, while shuffle[0..15] will return 16 distinct letters);
Avoid redundant local variables and especially return.
Here you go:
def my_hash
{
name: "John",
email: "johndoe#gmail.com",
password: ('a'..'z').to_a.sample(16).join
}
end
puts my_hash
Bonus:
I accidentaly found the third glitch in the original code. It should probably be:
def my_hash
{
name: "Brandon",
email: "brandon.elder#gmail.com",
password: ('a'..'z').to_a.sample(16).join
}
end
:)

How do I incorporate the index in variable name when looping with each_with_index?

How would I incorporate the index in a variable name so that I could access the different group objects?
This is my db/seeds.rb file:
u = User.create( email: "yeah#foo.com", password: "yeah", password_confirmation: "yeah")
groups_list = ["Math Club", "Science Class", "Economics Class"]
groups_list.each_with_index do |name, index|
"g#{index}" = u.groups.create(name: name)
end
When you start needing dynamically defined local variables you have a code smell and you know you should reconsider what you're doing.
It looks like you would be better served with a map call, converting the groups_list from an array of strings into an array of Group objects belonging to u:
groups_list.map { |name| u.groups.create name: name }
#=> [<Group name="Math Club">, …]
Then you can iterate through the groups or pass them into another method as an array, no trickery involved.

Rails - Create an helper method that print a specific attribute of all objects (render an array instead)

Sorry for this simple question but I am stuck here.
I am trying to create a helper method that simply prints for each object the attribute "name" of my Table "Term".
I tried this:
def display_name(terms)
terms.each do |term|
p term.name
end
end
But instead of printing each objects name, it prints an array for each object with all attributes.
As an example:
[#<Term id: 1, name: "test", definition: "first definition", created_at: "2011-07-21 14:52:12", updated_at: "2011-07-21 14:52:12">,
#<Term id: 2, name: "second test", definition: "blabla", created_at: "2011-07-20 18:00:42", updated_at: "2011-07-20 18:04:15">
I am trying to find what I can do with the documentation (content_tag, concat, collect) but it doesn't seem to provide the result I want..
Thanks for your explanation
The reason for this is because it does not actually print the name, it returns the value from terms.each since that was the last statement in the method.
I would probably use the map method to collect all the names into an array first and if you want a String instead of an Array then I would join them with whatever separator that is preferred, like this:
def display_name(terms)
terms.map(&:name).join ", "
end
You could also add a parameter to choose the separator if you like. Like this:
def display_name(terms, sep = ", ")
terms.map(&:name).join sep
end
# in view
display_name(collection, "<br/>")
By default it then uses a comma to separate them but you can manually choose something else.

Resources