Ruby/Rails Iterate through array and save to db? - ruby-on-rails

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

Related

How do I iterate through a table and create a hash for each value?

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.

How to create an array of methods in rails

def id_attachment_require_upload?
!object.id_attachment?
end
...
def work_attachment_require_upload?
!object.work_attachment?
end
I want to make it like below.
array = %w(id address work)
array.each do |a|
def #{a}_attachment_require_upload?
!object.#{a}_attachment?
end
end
Is there any way for me to create a array of methods automatically in rails to save me from the redundant work.
array = %w(id address work)
array.each do |a|
define_method "#{a}_attachment_require_upload?" do
!object.public_send("#{a}_attachment?")
end
end
Arup's answer looks like it's the way to go but I'm not sure if object.#{a}_attachment? will work. If it does, then I learned something new today. You can also use public_send.
array = %w[id address work]
array.each do |a|
define_method "#{a}_attachment_require_upload?" do
!object.public_send("#{a}_attachment?")
end
end

For array of ActiveRecord objects, return array of their attributes

#matched = [1, 2, 3]
Where each integer represents the id of an ActiveRecord object in the Inventory class. As a next step, I want to look at each of those objects and obtain the email of the parent User, but I'm not sure how to do it. Ideally I'd write something like:
Inventory.where(id: #matched).user.email
Because certainly, this statement would work if I only had a single id to look up. Since that doesn't work, I'm instead doing this
#email = []
#matched.each do |i|
#email << Inventory.find_by_id(i).user.email
end
Just wondering if there's an easier way.
Thanks!
If you only need the email addresses then you can use the pluck method:
Inventory.where(id: #matched).joins(:user).pluck("users.email")
class Inventory
def self.with_ids(ids)
sql = #matched.map{|id| "id = #{id}"}.join(" OR ")
where(sql)
end
def parent_email
user.email
end
end
Inventory.with_ids(#matched).map(&:parent_email)

Conditionally chaining where clauses in Rails ActiveRecord queries

I have a form that when filled has to trigger a particular query, depending on which parameters the form has, so I have a method in my model that I believe should look like this:
def form_query(params)
query = ''
if params.has_key?('size')
query = query.where(size: params['size'])
end
if params.has_key?('title')
query = query.where(title: params['title'])
end
# More conditionals depending on params.
end
My question is, what does query have to be at the beginning? I put query = '', but I am wondering what has to be the base case, so I can conditionally add more 'where' clauses.
Queries aren't strings; they're query objects. So you want something like
query = YourModel.scoped # Rails 3; in Rails 4, use .all
if params.has_key?('size')
query = query.where(size: params['size'])
end
etc.
Alternatively, you can update your code as below:
def self.form_query(params)
options = {}
fields = ["body", "title"].freeze ## Add other options
if params.present?
fields.each do |field|
options[field] = params[field] if params[field]
end
end
if options.present?
where(options)
else
all ## or nil if you don't want to show any records in view
end
end
Also, form_query should be a class method in your model.
Add more options in the fields array that you would like to query against.
It not only makes your code compact but also makes a single database call.
Here is a more condensed version of Kirti Thorat's version:
FIELDS = ["size", "title"].freeze ## Add other options
def self.form_query(params)
return all unless params.present?
options = params.select { |k, _v| FIELDS.include? k.to_s }
options.present? ? where(options) : all
end
I have done k.to_s so you can pass params keys as either strings or symbols.
If you want to return nil if no params are passed you can do this:
FIELDS = ["size", "title"].freeze ## Add other options
def self.form_query(params)
return unless params.present?
options = params.select { |k, _v| FIELDS.include? k.to_s }
where(options) if options.present?
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

Resources