Passing hash to #new results in array of values instead of correct value - ruby

With this setup in minitest,
def test_id
i = Item.new({
:id => 1,
:name => "Pencil",
:description => "You can use it to write things",
:unit_price => BigDecimal.new(10.99,4),
:created_at => Time.now,
:updated_at => Time.now,
:merchant_id => 2
})
assert_equal 1, i.id
end
For some reason, when created, calling the id attribute results in an array of all of the values:
[1,'Pencil','You can use it to write things',#<BigDecimal...>, 2018-07-24 14:43:36 -0600, 2018-07-24 14:43:36 -0600, 2]
instead of the integer 1.
In the item file, it looks like what you would expect
require 'bigdecimal'
require 'time'
class Item
attr_reader :id, :created_at, :merchant_id
attr_accessor :name, :description, :unit_price, :updated_at
def initialize(item_data)
#id = item_data[:id].to_i,
#name = item_data[:name],
#description = item_data[:description],
#unit_price = BigDecimal.new(item_data[:unit_price], 4),
#created_at = item_data[:created_at],
#updated_at = item_data[:updated_at],
#merchant_id = item_data[:merchant_id].to_i
end
end
Not really sure how this is happening.
Throwing a pry in the test method before the assertion and calling i results in
#<Item:0x00007f8cc48eb4f0
#created_at=2018-07-24 15:14:55 -0600,
#description="You can use it to write things",
#id=[1, "Pencil", "You can use it to write things", #<BigDecimal:7f8cc48eb4c8,'0.1099E2',18(27)>, 2018-07-24 15:14:55 -0600, 2018-07-24 15:14:55 -0600, 2],
#merchant_id=2,
#name="Pencil",
#unit_price=#<BigDecimal:7f8cc48eb4c8,'0.1099E2',18(27)>,
#updated_at=2018-07-24 15:14:55 -0600>
in the terminal.

It's your trailing commas in the initializer:
def initialize(item_data)
#id = item_data[:id].to_i, # <=
#name = item_data[:name], # <=
What they do is make ruby see the method like this:
#id = [item_data[id].to_i, #name = item_data[:name], ...]

It seems that the problem are the commas that you are adding at the end of each setting variable. Check with this code:
require 'bigdecimal'
require 'time'
class Item
attr_reader :id, :created_at, :merchant_id
attr_accessor :name, :description, :unit_price, :updated_at
def initialize(item_data)
#id = item_data[:id].to_i
#name = item_data[:name]
#description = item_data[:description]
#unit_price = BigDecimal.new(item_data[:unit_price], 4)
#created_at = item_data[:created_at]
#updated_at = item_data[:updated_at]
#merchant_id = item_data[:merchant_id].to_i
end
end

Related

How to pass argument into def_delegator

In order to return the correct roster for a store, I need to be able to pass the store_id argument into the delegator. Is this possible?
require "forwardable"
class Store
extend Forwardable
def_delegator :#roster, :names, :roster
attr_accessor :store_id
def initialize(store_id)
#store_id = store_id
#roster = Roster.new
end
end
class Roster
def names(store_id)
{
1 => ['Ned', 'Smith', 'Jerry', 'Ben'],
2 => ['Preeti', 'Jean', 'Sam', 'Lol']
}[store_id]
end
end
store = Store.new(1)
store.roster # => ['Ned', 'Smith', 'Jerry', 'Ben']

How to filter by foreign id and local attribute via belongs_to?

The following models are linked via belongs_to:
require 'mongoid'
class Sensor
include Mongoid::Document
field :sensor_id, type: String
validates_uniqueness_of :sensor_id
end
...
require 'mongoid'
require_relative 'sensor.rb'
class SensorData
include Mongoid::Document
belongs_to :sensor
field :date, type: Date
field :ozonMax1h, type: Float
field :ozonMax8hMittel, type: Float
index({ date: 1, sensor_id: 1 }, { unique: true })
end
Here is a Sinatra app which provides a few API paths based on these models:
require 'sinatra'
require 'csv'
require_relative './models/sensor.rb'
require_relative './models/sensor_data.rb'
configure do
Mongoid.load!('./mongoid.yml')
end
def prepare_for_export(sensor_data)
converted_data = sensor_data.asc(:date).map do |e|
{
sensor_id: e.sensor.nil? ? :null : e.sensor.sensor_id,
date: e.date,
ozonMax1h: e.ozonMax1h,
ozonMax8hMittel: e.ozonMax8hMittel
}
end
converted_data
end
def convert_to_json(sensor_data)
prepare_for_export(sensor_data).to_json
end
def convert_to_csv(sensor_data)
data = prepare_for_export sensor_data
csv_string = CSV.generate do |csv|
csv << data.first.keys
data.each do |hash|
csv << hash.values
end
end
csv_string
end
def get_recent
max_date = SensorData.max(:date)
SensorData.where(date: max_date)
end
def get_for_year(year)
SensorData.where(:date.gte => Date.new(year, 1, 1)).where(:date.lte => Date.new(year, 12, 31))
end
def get_for_sensor(sensor)
foo = SensorData.where(sensor_id: sensor)
puts "hallo"
return foo
end
get '/api/v1/stations' do
content_type :json
Sensor.all.map { |e| {sensor_id: e.sensor_id} }.to_json
end
get '/api/v1/sensordata/:year' do
content_type :json
convert_to_json get_for_year(params[:year].to_i)
end
get '/api/v1/sensordata/:year/csv' do
convert_to_csv get_for_year(params[:year].to_i)
end
get '/api/v1/recent' do
content_type :json
convert_to_json get_recent
end
I would like to output the SensorData for a particular sensor such as here:
/api/v1/stations/:sensor_id/sensordata/:year/csv
I am not sure what you are trying to do or even if you are still looking for an answer but here it goes. Something seems wrong with the models in the example you have here. Sounds like part of what you are doing would work if Sensor knows about sensor_data. So might need to add this to Sensor class:
has_many :sensor_data
Though the singular of data is datum. The class would be expected to be SensorDatum. If you can't change it, you need to tell Mongoid the class_name to expect in the has_many is actuall SensorData.
You CAN specify foreign_key in Mongoid with belongs_to.
You CANNOT filter with the belongs_to like you can with ActiveRecord, but you can use scopes outside of the belongs_to to get the same effect. Exampe:
belongs_to :sensor
scope :for_year, -> (year) { where(:date.gte => Date.new(2015,1,1)).where(:date.lte => Date.new(2015, 12, 31))}
or
belongs_to :sensor
def self.for_year year
where(:date.gte => Date.new(year,1,1)).where(:date.lte => Date.new(year, 12, 31))
end
So your query would become something like this:
sensor = Sensor.find_by(sensor_id: params[:sensor_id])
sensor.sensor_data.for_year(2015)

Sequel one_to_one association

Referencing Sequel's docs I've set up a one_to_one association between a Position and a Company.
class Position < Sequel::Model
one_to_one :company
end
class Company < Sequel::Model
many_to_one :position
end
When I try to get a company through a position I get nil, although I can find the company with a direct Sequel query.
p = Position.first #=> #<Position #values={:id=>1}>
p.company #=> nil
Company.where(position_id: p.id).first #=> #<Company #values={:id=>1, position_id: 1}>
You look confused about the relations or the schema. Unless you have a very specific business case, a company has many positions, which makes one-to-many relation and many positions can belong to one company, which makes many-to-one.
Here's how I see it:
require 'sqlite3'
require 'sequel'
DB = Sequel.connect('sqlite://companies')
DB.create_table :companies do
primary_key :id
String :name
end
DB[:companies].insert(name: 'Acme')
DB.create_table :positions do
primary_key :id
String :name
foreign_key :company_id, :companies
end
DB[:positions].insert(name: 'CEO', company_id: DB[:companies].first[:id])
DB[:positions].insert(name: 'CTO', company_id: DB[:companies].first[:id])
class Company < Sequel::Model
one_to_many :positions
end
class Position < Sequel::Model
many_to_one :company
end
p Company.first.positions
# [#<Position #values={:id=>1, :name=>"CEO", :company_id=>1}>, #<Position #values={:id=>2, :name=>"CTO", :company_id=>1}>]
p Position.first.company
# #<Company #values={:id=>1, :name=>"Acme"}>
I can get your associations to work:
require 'sequel'
DB = Sequel.connect('sqlite://test.db')
unless DB.table_exists? (:positions)
DB.create_table :positions do
primary_key :id
string :name
foreign_key :company_id
end
end
unless DB.table_exists?(:companies)
DB.create_table :companies do
primary_key :id
string :name
foreign_key :position_id
end
end
class Position < Sequel::Model
one_to_one :company
end
class Company < Sequel::Model
many_to_one :position
end
ford = Company.create(name: "Ford")
vw = Company.create(name: "VW")
accountant.company = ford
p accountant.company #=> #<Company #values={:id=>53, :name=>"Ford", :position_id=>35}>
puts accountant.id #=> 35
accountant.add_company(vw) #=> undefined method `add_company' for #<Position...
I'll add that the Sequel docs for associations are terrible. They need to include a complete example--including how to create the objects so that they are associated with each other.

DateTime and DataMapper

Problem
I'm essentially trying to save +4 hours from now in DM. I think the DateTime is correct, but the DataMapper doesn't work properly. Any ideas?
Controller
p DateTime.now
t = DateTime.now + params[:hours] / 24
p t
reward = #player.work params[:hours]
action = Action.new(:player => #player, :type => 0, :completed_at => t, :reward => reward)
model
class Action
include DataMapper::Resource
property :id, Serial
property :type, Integer
property :completed_at, DateTime
property :reward, Integer
TYPES = {
0 => "Work",
1 => "Arena",
2 => "Quest"
}
validates_with_method :type, :method => :valid_type?
def valid_type?
if TYPES.key? self.type.to_i
true
else
[false, "Invalid action type."]
end
end
def get_type
case TYPES[self.type]
when "Work"
"you're working"
when "Arena"
"in the arena"
when "Quest"
"in a quest"
end
end
belongs_to :player
end
try:
DateTime.now + (params[:hours] / 24.0)

ActiveRecord STI delete doesn't work correctly

I want to store two models using active record, but delete doesn't work as expected.
Evaluation has id, name and description
and SqlEvaluation has additional two columns of query_string and database.
I want to use those two tables, and eval_typ_id is used to distinguish which subclass should be used: 1 for SqlEvaluation.
create table eval (
eval_id int,
eval_name varchar,
eval_desc varchar,
eval_typ_id int
);
create table sql_eval (
eval_id int
query_str varchar
database varchar
);
After some research, I used the following code, it works well except "delete", which didn't delete the row in sql_eval. I cannot figure out where is wrong?
require 'rubygems'
require 'active_record'
require 'logger'
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.establish_connection(:adapter => "ibm_db",
:username => "edwdq",
:password => "edw%2dqr",
:database => "EDWV2",
:schema => "EDWDQ" )
class Eval < ActiveRecord::Base
set_table_name "eval"
set_primary_key :eval_id
TYPE_MAP = { 1 => 'SqlEval' }
class << self
def find_sti_class(type)
puts "#{type}"
super(TYPE_MAP[type.to_i])
end
def sti_name
TYPE_MAP.invert[self.name]
end
end
set_inheritance_column :eval_typ_id
end
class SqlEval < Eval
has_one :details, :class_name=>'SqlEvalDetails', :primary_key=>:eval_id, :foreign_key=>:eval_id, :include=>true, :dependent=>:delete
default_scope :conditions => { :eval_typ_id => 1 }
end
class SqlEvalDetails < ActiveRecord::Base
belongs_to :sql_eval, :class_name=>'SqlEval',
:conditions => { :eval_type_id => 1 }
set_table_name "sql_eval"
set_primary_key :eval_id
end
se = SqlEval.find(:last)
require 'pp'
pp se
pp se.details
# Eval.delete(se.eval_id)
se.delete
Sorry for messing the code. It is first time to post for me. Here is the code.
require 'rubygems'
require 'active_record'
require 'logger'
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.establish_connection(:adapter => "ibm_db",
:username => "edwdq",
:password => "edw%2dqr",
:database => "EDWV2",
:schema => "EDWDQ" )
class Eval < ActiveRecord::Base
set_table_name "eval"
set_primary_key :eval_id
TYPE_MAP = { 1 => 'SqlEval' }
class << self
def find_sti_class(type)
puts "#{type}"
super(TYPE_MAP[type.to_i])
end
def sti_name
TYPE_MAP.invert[self.name]
end
end
set_inheritance_column :eval_typ_id
end
class SqlEval < Eval
has_one :details, :class_name=>'SqlEvalDetails', :primary_key=>:eval_id, :foreign_key=>:eval_id, :include=>true, :dependent=>:delete
default_scope :conditions => { :eval_typ_id => 1 }
end
class SqlEvalDetails < ActiveRecord::Base
belongs_to :sql_eval, :class_name=>'SqlEval',
:conditions => { :eval_type_id => 1 }
set_table_name "sql_eval"
set_primary_key :eval_id
end
se = SqlEval.find(:last)
e = Eval.where(:eval_id => 26)
require 'pp'
pp se
pp e
pp se.details
# Eval.delete(se.eval_id)
se.delete

Resources