Ruby on Rails: Assigning attribute values to generic model - ruby-on-rails

I am trying to write a ruby on rails function that will create a new object for any model. Here is what I have so far
def create_populated_object(model)
test_object = model.new
model.columns.each do |column|
attr_name = column.name
attr_type = column.type
#test_object.assign_attributes(attr_name+':'+ "9")
puts "#{':'+attr_name} => #{attr_type}"
if attr_type.to_s == 'integer'
b = '{:' + attr_name.to_s + '=>' + 9.to_s + '}'
puts b
test_object.assign_attributes(b)
puts "it worked"
elsif attr_type.to_s == 'string'
puts "string"
elsif attr_type.to_s == 'datetime'
puts "date time"
elsif attr_type.to_s == 'boolean'
puts "boolean"
elsif attr_type.to_s == 'text'
puts "text"
else
puts "UNKNOWN ATTRIBUTE TYPE"
end
end
puts test_object
end
In my example, id is the first attribute of the model. I try to assign the value 9 to it, but I keep getting this error:
NoMethodError: undefined method `stringify_keys' for "{:id=>9}":String
Anyone know how to fix this?

You need to send a Hash object instead of a string to the method:
b = { attr_name => 9 }
test_object.assign_attributes(b)

assign_attributes expects a hash of attributes to be passed to it. You are passing it a string. Would it be problematic to simply say b = {attr_name.to_sym => 9}?

Related

Ruby rails object is nil, yet controller logic acting as if object is not nil

I have an an object Search with a method listings that returns an array of hashes if there are search results, otherwise it returns an empty array. In the event there is any empty array, I need to skip some code and go straight to the show page. I've tried object.nil? object.empty? object.present? all with the same outcome....the object which is supposed to be nil is treated as non-nil.
Controller code:
def show
#search = Search.find(params[:id])
#results = #search.listings
if #results.last.present?
if #results.last[0] == "p" || #results.last[0] == "s" || #results.last[0] == "d"
p "#results.pop is either p, s, or d"
#sort_column = #results.pop
#grade = #sort_column.gsub(/[^0-9,.]/, "") unless #results.last[0] == "d"
end
end
end
show action results in
undefined method `[]' for nil:NilClass
Extracted source (around line #21):
19 p "#results.pop is either p, s, or d"
20 #sort_column = #results.pop
21 #grade = #sort_column.gsub(/[^0-9,.]/, "") unless #results.last[0] == "d"
22 end
23 end
24 end
but, the server interface verifies that #results.last is nil:
>> #results
=> []
>> #results.last
=> nil
>> #results.last.present?
=> false
>> #results.last[0]
NoMethodError: undefined method `[]' for nil:NilClass
from /Users/tomb/Projects/schoolsparrow/app/controllers/searches_controller.rb:21:in `show'
>>
I'm at a loss as to how to logic is getting past the results.last.present? when results.last is nil.
If you're testing to see whether or not your array has any values in it, try:
#results.any?
An empty array is not nil, which is why your checks are failing.
EDIT:
A concise explanation of nil v. empty v. blank in Ruby on Rails
Why don't you check your condition on #results.present? and not #results.last.present?.
#results.last would throw a NoMethodError if #result is nil
To check if an array has elements use .any? or its opposite twin .empty?:
irb(main):006:0> [].empty?
=> true
irb(main):007:0> [].any?
=> false
.present? and .presence work on arrays but they are really more idiomatically correct for hashes like the params.
def show
#search = Search.find(params[:id])
#results = #search.listings
if #results.any? && ['p', 's', 'd'].include?(#results.last[0])
p "#results.pop is either p, s, or d"
#sort_column = #results.pop
#grade = #sort_column.gsub(/[^0-9,.]/, "") unless #results.last[0] == "d"
end
end

ruby scripts - (NameError) undefined local variable or method `null' for main:Object

My code
require "json"
require "erb"
flowvar = $workflowvar
path = 'src/main/resources/'+$workflowvar+'.drl'
rule = ""
File.open(path,"w") do |f|
f.puts "package com.drools.demo\;"+"\n"+"import org.mule.MessageExchangePattern\;"+"\n"+"import com.drools.demo.cashliquidassets\;"+"\n"+"global org.mule.module.bpm.MessageService mule\;"+"\n"+
"dialect \"mvel\""+"\n"+"dialect \"java\""+"\n"+"declare cashliquidassets"+"\n"+"#role\(\'event\'\)"+"\n"+"end"+"\n"
f.close
end
def concateRule(attribute,val)
if(val==null || val=="")
return "";
end
if(attribute != null)
if (attribute == "taxonomy_code" || attribute == "parent_taxonomy_code" || attribute == "report_name")
return "";
end
end
if val.start_with('<>')
return attribute+" != "+val[3,val.length].strip
elsif val.start_with('>')
return attribute+" > "+val
elsif val.start_with('<')
return attribute+" < "+val
elsif val.include? ","
return attribute+".contains("+val+"\)"
else
return attribute+" == "+ val
end
end
json = JSON.parse($payload)
json.each do |hash1|
hash1.keys.each do |key|
hash1[key].each do |inner_hash,value|
#inner_hash = inner_hash
#values = value
str = concateRule #inner_hash,$values
end
end
end
Compile is working fine, but in runtime, I am getting this following error. Any suggestions
Root Exception stack trace:
org.jruby.exceptions.RaiseException: (NameError) undefined local
variable or method `null' for main:Object
at RUBY.concateRule(<script>:15)
at RUBY.block in (root)(<script>:43)
at org.jruby.RubyHash.each(org/jruby/RubyHash.java:1350)
at RUBY.block in (root)(<script>:40)
at org.jruby.RubyArray.each(org/jruby/RubyArray.java:1735)
at RUBY.block in (root)(<script>:39)
at org.jruby.RubyArray.each(org/jruby/RubyArray.java:1735)
at RUBY.<main>(<script>:38)
You need to use nil instead of null.
So, just replace it.
Following the conversation in the comments above, here is how I would write the method:
def concat_rule(attribute, val)
val = val.to_s
if val == '' || ['taxonomy_code', 'parent_taxonomy_code', 'report_name'].include?(attribute)
return ''
end
if val.start_with?('<>')
"#{attribute} != #{val[3..-1].strip}"
elsif val.start_with?('>')
"#{attribute} > #{val}"
elsif val.start_with?('<')
"#{attribute} < #{val}"
elsif val.include?(',')
"#{attribute}.contains(#{val})"
else
"#{attribute} == #{val}"
end
end
A few notes:
Using snake_case method names and 2 space tabs, is a very strongly adhered to style guide in the ruby community.
Similarly, you can make use of ruby's implicit return, to shorten the code: The final value at the end of a method is returned automatically.
Adding val = val.to_s to the top of this method simplifies the rest of the code; eliminating the need to repeatedly convert to a string or perform nil checks.
You can use ruby's string interpolation ("#{code-to-evaluate}") syntax as a more elegant way to define strings than repeated use of + for concatenation.

Filters and chaining of them

I have two filters that get checked for my Rails model called Items. If both filters are enabled, Ie: certain params are passed then it filters down the Items based on the first one and then should use the results of the first filter as the basis to filter from the second. But it doesn't like me calling .where on the instance variable of #items which is being passed to my view? Any thoughts?
Error is :
undefined method `where' for #
Code:
#coasters = Coaster.all
if params[:type]
type = params[:type]
if type == 'powered'
#coasters = #coasters.where("style = ?", "powered")
else
#coasters = #coasters.where("material LIKE ?", params[:type])
end
end
if params[:letters]
letters = params[:letters]
if letters == '#'
#coasters = #coasters.all.select { |r| /^[0-9].*/ =~ r.name }
else
letters = letters.split('-')
lettersLower = (letters[0]..letters[1]).to_a
lettersUpper = (letters[0].upcase..letters[1].upcase).to_a
letters = lettersLower.concat(lettersUpper)
conditions = (letters.map{ |letter| " name ILIKE '#{letter}%' " }.join('OR'))
#coasters = #coasters.where(conditions)
end
end

Rails based on condition assign model to variable

I have the following method:
def self.get_rec(product, type)
if type == "A"
db = Pwvav
elsif type == "B"
db = Pwbab
elsif type == "C"
db = Pwvub
else type == "D"
db = Tic
db.find_by_id(product.id).recommendation.split(",").each do |rec|
r = Recommendation.find_by_id(rec)
pr = Model.new(:rating_set => rating_set.id, :recommendation_id => r.id, :product_id => product.id)
pr.save
end
end
end
When I run the method, the db.find is not working as I expect. If replace db.find_by_id(product.id).recommendation.split(",").each do |rec| with Pwvav.find_by_id(product.id).recommendation.split(",").each do |rec| for example, it works. How do I chose which model to call based on what the type equals?
your error, if I'm right, is with your structure. the find_by_id code is inside the else so it doesn't create other records when type is not 'D'. Try the following code which I think is more readable
def self.get_rec(product, type)
db = case type
when 'A' then Pwvav
when 'B' then Pwbab
when 'C' then Pwvub
when 'D' then Tic
end
db.find_by_id(product.id).recommendation.split(",").each do |rec|
r = Recommendation.find_by_id(rec)
pr = Model.new(rating_set: rating_set.id, recommendation_id: r.id, product_id => product.id)
pr.save
end
end
You haven't close your "if - elsif - else condition, then the last block with the find, find_by_id and your new is only executed when type == 'D'.
Insert an end after
db = Tic

Railswhat to do about empty columns in my database? Throwing an error:ArgumentError: invalid value for Float(): ""

Im trying to read a column of String values from my DB. Im trying to convert them to floats. I have written the following method to do that
def initialize (db_listings)
db_listings.each do |listing|
name = listing.name
index = listing.id
lat_string = listing.latitude
long_string = listing.longitude
puts "name = #{name}"
puts "index = #{index}"
puts "Converting #{lat_string} to float"
puts "Converting #{long_string} to float"
if(lat_string == nil || long_string == nil )
lat_float = Float(9999)
long_float = Float(9999)
else
lat_float = Float(lat_string)
long_float = Float(long_string)
end
puts "Now printing floats"
puts lat_float
puts long_float
end
end
But I get the following error:
Throwing an error:ArgumentError: invalid value for Float(): ""
This is because it encountered an empty entry for that column.
My question is : WHy did the if else statement in my method not catch it?
How do I adjust my method for empty/invalid values in the database?
Thanks
From the error message I presume lat_string and long_string are empty strings rather than nil. You could use blank? to catch both nil and empty strings:
if(lat_string.blank? || long_string.blank?)
lat_float = Float(9999)
long_float = Float(9999)
else
lat_float = Float(lat_string)
long_float = Float(long_string)
end

Resources