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
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.
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
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
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
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