How do I iterate through a table and create a hash for each value? - ruby-on-rails

I have two tables. One for accounts and another for keywords. I would like to iterate over all of the keywords and store each one in a hash--grouped by the account ID that added the keyword. The code that I have below doesn't add each keyword to the hash. For example, I have an account that has 2 keyword entries. My code skips the first entry and only adds the second entry to the hash.
#keyword_hash = {}
#account.each do |key, value|
#keywords.where(:profile_id => key).each do |keyword|
#keyword_hash[key] = keyword.entry
end
end
puts #keyword_hash
How can I modify the above code so that I add each keyword entry for a particular account to the hash?
I would like to be able to do #keyword_hash[6] and get keyword1, keyword2, keyword3, etc. for that account. Thanks!

Make an array [keyword1, keyword2, keyword3, etc.] and then add it to hash
**
#keyword_hash = {}
#account.each do |key, value|
arr = []
#keywords.where(:profile_id => key).each do |keyword|
arr << keyword.entry
end
#keyword_hash[key] = arr
end
puts #keyword_hash
**

Try this code
#keyword_hash = Hash.new { |h, k| h[k] = [] }
#account.each do |key, value|
#keywords.where(:profile_id => key).each do |keyword|
#keyword_hash[key] << keyword.entry
end
end
puts #keyword_hash
The mistake you are doing is that you are storing a single value against each key in your #keyword_hash hash. so when your code writes second value against account key, it replaces the previous value instead of adding second one.
Edit: Thank you #mudasobwa for correction regarding shared default value.

#keyword_hash = Hash.new { |hash, key| hash[key] = [] }
#keywords.group_by{ |k| k.profile_id }.each do |key,value|
#keyword_hash[key] = value.map(&:entry)
end
puts #keyword_hash
After doing some more research, I found the above solution. I used #jvillian's suggestion about group_by, and I found this article that showed me how to initialize the hash.

Related

Iterate through array of column names to pass to uniq.pluck()?

I have multiple columns I need to pull unique values from and compile an array of each unique value. Using uniq.pluck(:column_name) works, but how do I iterate over an array of column names?
react = []
fields = [reactivity_1, reactivity_2, reactivity_3, reactivity_4]
fields.each do |field|
puts "Parsing #{field}"
Raw.all.uniq.pluck(field).each do |r|
unless react.include? r
puts "Adding #{r} to Array."
react << r
else
puts "#{r} Exists."
end
end
end
Error:
NameError: undefined local variable or method `reactivity_1' for main:Object
You will need to make the column names strings or symbols, like this Ruby thinks it is a local varaible or method.
react = Set.new
fields = [:reactivity_1, :reactivity_2, :reactivity_3, :reactivity_4]
fields.each do |field|
puts "Parsing #{field}"
Raw.all.uniq.pluck(field).each do |r|
react << r
end
end
If you want to make sure that a collection does not contain duplicate, you can use a Set:
require "set"
set = Set.new
set << "foo"
set << "bar"
set << "bar"
puts set.size #> 2
I've rewritten your code sample to use Set.
Can you describe what you are trying to achieve? Perhaps there is an easier way to get the data out of the DB.

Ruby/Rails Iterate through array and save to db?

I want to put each string from #enc into each field of column_name as a value
#enc=["hUt7ocoih//kFpgEizBowBAdxqqbGV1jkKVipVJwJnPGoPtTN16ZAJvW9tsi\n3inn\n", "wGNyaoEZ09jSg+/IclWFGAXzwz5lXLxJTUKqCFIiOy3ZXRgdwFUsNf/75R2V\nZm83\n", "MPq3KSzDzLvTeYh+h00HD+5FAgKoNksykJhzROVZWbIJ36WNoBgkSoicJ5wx\nog0g\n"]
Model.all.each do |row|
encrypted = #enc.map { |i| i}
row.column_name = encrypted
row.save!
end
My code puts all strings from array #enc into a single field?
I do not want that.
Help
Rails by default won't allow mass assignment. You have to whitelist parameters you want permitted. Have you tried doing something like the following?
#enc.each do |s|
cparams = create_params
cparams[:column_name] = s
Model.create(cparams)
end
def create_params
params.permit(:column_name)
end
You will need to specify the column names you are saving to. By setting each column separately you can also avoid mass-assignment errors:
#enc=["hUt7ocoih//kFpgEizBowBAdxqqbGV1jkKVipVJwJnPGoPtTN16ZAJvW9tsi\n3inn\n", "wGNyaoEZ09jSg+/IclWFGAXzwz5lXLxJTUKqCFIiOy3ZXRgdwFUsNf/75R2V\nZm83\n", "MPq3KSzDzLvTeYh+h00HD+5FAgKoNksykJhzROVZWbIJ36WNoBgkSoicJ5wx\nog0g\n"]
model = Widget.new
column_names = [:column1, :column2, :column3]
#enc.each_with_index do |s, i|
model[column_names[i]] = s
end
model.save
I think you are looking for something like this:
#enc.each do |str|
m = Model.new
m.column_name = str
m.save
end

Ruby on Rails: Iterate Through Nested Params

I want to iterate through submitted params. Params array could be up to three level. Currently I can iterate only first level like this.
params[:job].each do |v, k|
#do something with k value, only if it's string. If it's array then find its string value.
end
How do I iterate params when you don't know what you are expecting?
One easy way is to use is_a?
if v.is_a? Array
# do whatever
elsif v.is_a? String
# do whatever
else
# something else
end
Some kind of recursive solution might be best here, such as:
def handle_hash hash
hash.each do |k, v|
if v.is_a? Hash
handle_hash v
elsif v.is_a? String
# handle string
end
end
end
And then you can just call handle_hash params[:job]
def nested_params(nested_hash={})
nested_hash.each_pair do |k,v|
case v
when String, Fixnum then
dosomething(v)
when Hash then nested_params(v)
else raise ArgumentError, "Unhandled type #{v.class}"
end
end
end

Rails: How to initialize an object with the attributes in strings?

Probably been working on this too long, sloppy design, or both. My issue is I have a model I wish to initialize. The object has like 52 attributes, but I'm only setting a certain ~25 depending on which object I've just scanned. When I scan an object I get the columns and match them up with a hash_map I've created.
Example Hash Map
This just matches the scanned text to their respective attribute name.
hash_map = {"Pizza."=>"pizza_pie","PastaBowl"=>"pasta_bowl","tacos"=>"hard_shell_taco","IceCream"=>"ice_cream","PopTarts"=>"pop_tart"}
What I want to do
menu = RestaurantMenu.new(pizza_pie => var1, pasta_bowl => var2, ...)
My only problem is in my code at the moment I have this...
t.rows.each do |r|
for i in 0..r.length-1
#hash_map[t.combined_columns[i]] => r.[i]
puts "#{hash_map["#{t.combined_columns[i]}"]} => #{r[i]}"
end
end
the puts line displays what I want, but unsure how to get that in my app properly.
Here is several ways to fix this:
hash_map = {"Pizza."=>"pizza_pie","PastaBowl"=>"pasta_bowl","tacos"=>"hard_shell_taco","IceCream"=>"ice_cream","PopTarts"=>"pop_tart"}
attributes.each do |attribute, element|
message.send((attribute + '=').to_sym, hash_map[element])
end
or like this:
class Example
attr_reader :Pizza, :PastaBowl #...
def initialize args
args.each do |k, v|
instance_variable_set("##{k}", v) unless v.nil?
end
end
end
for more details click here
I ended up doing the following method:
attributes = Hash[]
attributes["restaurant"] = tmp_basic_info.name
attributes["menu_item"] = tmp_basic_info.item_name
t.rows.each do |r|
for i in 0..r.length-1
attributes["other"] = t.other_information
attributes[hash_map[t.combined_columns[i]] = r[i]
end
row = ImportMenuItem.new(attributes)
row.save
end

Rails Array Conditions Query

I've written the following method to combine the References of Sections model and it's children:
def combined_references
ids = []
ids << self.id
self.children.each do |child|
ids << child.id
end
Reference.where("section_id = ?", ids)
end
But section.combined_references returns the following error:
Mysql2::Error: Operand should contain 1 column(s): SELECT `references`.* FROM `references` WHERE (section_id = 3,4)
It seems to have collected the correct values for ids, have I structured the query incorrectly?
Transform last line to:
Reference.where(section_id: ids)
and it should produce:
SELECT `references`.* FROM `references` WHERE section_id IN (3,4)
And you can shorten your code by one line with :
ids = []
ids << self.id
to
ids = [self.id]
it's invalid statement
WHERE (section_id = 3,4)
correct would be
WHERE (section_id in (3,4))
Please use:
Reference.where(:section_id => ids)
You can try something like this instead:
def combined_references
ids = self.children.map(&:id).push(self.id)
Reference.where(section_id: ids)
end
You can also query the database with:
Reference.where("section_id in (?)", ids)
The following has the most readability in my opinion:
def combined_references
Reference.where(section_id: self_and_children_ids)
end
private
def self_and_children_ids
self.children.map(&:id).push(self.id)
end

Resources