Rails: can't convert ActiveRecord::Associations::BelongsToAssociation into String - ruby-on-rails

This rails project is very bare-bones, just begun, so I haven't done any weird loopholes or patching.
The model, to_s replaces school with bar if nil:
class Department < ActiveRecord::Base
belongs_to :school
def to_s
"foo" + (school || "bar")
end
end
Says the view:
can't convert ActiveRecord::Associations::BelongsToAssociation into String
about the to_s statement
but in script/console, I can take a Department d where school==nil and say
"foo" + (d.school || "bar")
and get "foobar"

The problem is when school is not nil. It is not a string, so you can't add it to "foo". Here are some options to fix it:
"foo" + (school || "bar").to_s
"foo" + (school ? school.to_s : "bar")
"foo" + (school.try(:to_s) || "bar")
"foo#{school || 'bar'}"

Try self.school

Related

How to convert string to existing attribute in model when creation

I got a array of strings, I want to retrieve for each the attribute during the creation of the post.
My array = ["_646_maturity", "_660_maturity", "_651_maturity", "_652_maturity", "_641_maturity"]
class Audit < ApplicationRecord
belongs_to :user
before_save :calculate_scoring
def calculate_scoring
scoring = []
models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize.constantize rescue nil}
columns = models.collect{|m| m.column_names rescue nil}
columns[2].each do |c|
if c.include? "maturity"
Rails.logger.debug 'COLUMN : '+c.inspect
scoring.push(c)
end
end
getMaturity = ""
scoring.each do |e|
getMaturity = e.to_sym.inspect
Rails.logger.debug 'MATURITY : '+getMaturity
end
end
end
The log print > 'MATURITY : :_651_maturity'
I'm looking to the value of :_651_maturity who is a attribute of my post.
I tried .to_sym but it's not working..
Thanks for the help!
Inside calculate_scoring you can use self to point to the record you are saving. So self._651_maturity = <some_value>, self[:_651_maturity] = <some_value> and self['_651_maturity'] are all valid methods to set _651_maturity.
Also, you can do something like:
my_attrib = '_651_maturity'
self[my_attrib] = 'foo'

Ruby on Rails: Assigning attribute values to generic model

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}?

In ruby, how do you write item.nil? ? nil : item.id.to_s

There has to be better way to write item.nil? ? nil : item.id.to_s. Anyone know it?
Yes it is possible :
item && item.id.to_s
Example :
a = 23
a && a.to_s # => "23"
a = nil
a && a.to_s # => nil
I would use unless:
item.id.to_s unless item.nil?
I case the condition is false, this expression evaluates to nil.
You could also do something like:
item.id.to_s if item
Since you have "ruby-on-rails tag", on rails you can do item.try(:id).try(:to_s)
Here's an example
require 'active_support/core_ext/object/try'
class Item
attr_accessor :id
end
item= Item.new
item.id= 42
p item.try(:id).try(:to_s)
item= nil
p item.try(:id).try(:to_s)
"42"
nil
EDIT: Not the best way by far, see below comments.
After the below monkey patch nil.id.to_s will start to return nil.
class NilClass
def id
self
end
def to_s
self
end
end

How to get result of multiples queries in a scope?

I have a dummy_names table which contains random first_names and last_names. In the db, where there is a first_name for an entry, the last_name is NULL and vice versa.
I'm trying to write a scope that returns a random name (a random first_name + a random last_name from that able).
What am I doing wrong here...?
scope :random_name, lambda {
fname = self.where('first_name IS NOT NULL').first
lname = self.where('last_name IS NOT NULL').first
fname.first_name.to_s + " " + lname.last_name.to_s
}
here we go
#in your initializer
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
#in your model
def self.random_name
"#{self.where('first_name IS NOT NULL').random.first_name} #{self.where('last_name IS NOT NULL').random.last_name}"
end

How do I inspect the class type of attributes in ruby?

How do I create a method like:
def process_by_type *things
things.each {|thing|
case thing.type
when String
when Array
when Hash
end
end
}
end
I know I can use kind_of?(Array), etc. But I think this would be cleaner, and I cant' find a method for it on the Class:Object documentation page.
Using the form of case statement like what you're doing:
case obj
when expr1
# do something
when expr2
# do something else
end
is equivalent to performing a bunch of if expr === obj (triple-equals comparison). When expr is a class type, then the === comparison returns true if obj is a type of expr or a subclasses of expr.
So, the following should do what you expect:
def process_by_type *things
things.each {|thing|
case thing
when String
puts "#{thing} is a string"
when Array
puts "#{thing} is an array"
when Hash
puts "#{thing} is a hash"
else
puts "#{thing} is something else"
end
}
end
Try .class:
>> a = "12"
=> "12"
>> a.class
=> String
>> b = 42
=> 42
>> b.class
=> Fixnum

Resources