Summing values from a hash - ruby-on-rails

I have a model where I am am storing some related data in a hash like this:
line_items_attributes"=>[{"major"=>"8762", "minor"=>"322", "description"=>"Engineering", "amount"=>"200000", "active"=>"1"}, {"major"=>"8762", "minor"=>"445", "description"=>"Tanks", "amount"=>"2100000", "active"=>"1"}, {"major"=>"8762", "minor"=>"500", "description"=>"Pipe, Valves & Fittings", "amount"=>"150000", "active"=>"1"}]
I went this way to avoid another related model etc.
I amy playing with this prototype from this website:
http://daniel.fone.net.nz/blog/2013/10/19/prototyping-web-applications-in-rails-4/?utm_source=rubyweekly&utm_medium=email
Anyway I want to all the 'amount' values. I have Googled a few solutions but I don't know enough about hashes to figure this out.
I tried:
2.0.0-p247 :053 > line_items_attributes.inject(0) {|sum, hash| sum + hash["amount"]}
TypeError: no implicit conversion of String into Integer
from (irb):53:in `[]'
from (irb):53:in `block in irb_binding'
from (irb):53:in `each'
from (irb):53:in `inject'
from (irb):53
from /Users/dan/.rvm/gems/ruby-2.0.0-p247#global/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
from /Users/dan/.rvm/gems/ruby-2.0.0-p247#global/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
from /Users/dan/.rvm/gems/ruby-2.0.0-p247#global/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
I even tried adding hash["amount"].to_i but that didn't work. I think I am close but sure I am missing something obvious to someone more experienced.
On a side note I have seen other hash notations show such as:
line_items_attributes"=>[{major:"8762", minor:"322" etc. is there an advantage to this?

This works for me:
2.0.0p247 :028 > line_items_attributes = [{"major"=>"8762", "minor"=>"322", "description"=>"Engineering", "amount"=>"200000", "active"=>"1"}, {"major"=>"8762", "minor"=>"445", "description"=>"Tanks", "amount"=>"2100000", "active"=>"1"}, {"major"=>"8762", "minor"=>"500", "description"=>"Pipe, Valves & Fittings", "amount"=>"150000", "active"=>"1"}]
=> [{"major"=>"8762", "minor"=>"322", "description"=>"Engineering", "amount"=>"200000", "active"=>"1"}, {"major"=>"8762", "minor"=>"445", "description"=>"Tanks", "amount"=>"2100000", "active"=>"1"}, {"major"=>"8762", "minor"=>"500", "description"=>"Pipe, Valves & Fittings", "amount"=>"150000", "active"=>"1"}]
2.0.0p247 :036 > line_items_attributes.inject(0) {|sum, hash| sum += hash["amount"].to_i; sum}
=> 2450000

D'oh! After looking again I missed the fact that the data being stored was actually:
{"line_items_attributes"=>[{"major"=>"8762", "minor"=>"322", "description"=>"Engineering", "amount"=>"200000", "active"=>"1"}, {"major"=>"8762", "minor"=>"445", "description"=>"Tanks", "amount"=>"2100000", "active"=>"1"}, {"major"=>"8762", "minor"=>"500", "description"=>"Pipe, Valves & Fittings", "amount"=>"150000", "active"=>"1"}]}
So now I ran this:
Model.find(1).data["line_items_attributes"].inject(0) {|sum, hash| sum + hash["amount"].to_i}
and all is good. I probably don't need to store it that way but I was just using that prototype tutorial as an example.
Thanks to those who took the time to look at this. I had figured it out on my own... sort of.

Related

money-rails, Money#== supports only zero numerics

I'm using the money-rails gem in my Rails application. It have worked perfectly until now, but I've recently started getting the following error:
Money#== supports only zero numerics
I'm not really sure what caused this or how to solve it. I have recently run bundle update so I guess that something have been updated. My gemfile looks like this:
gem 'money-rails', '~>1'
gem 'eu_central_bank', "~>1.3.0"
My implementation looks like this:
# model
monetize :price_in_cents
# fetch / converting currencies
eu_bank = EuCentralBank.new
Money.default_bank = eu_bank
eu_bank.update_rates
converted_price = eu_bank.exchange_with(Money.new(price_to_convert * 100, from_currency), to_currency)
This have as I mentioned worked before, so I'm not sure what is breaking it.
Any ideas?
Update
To test I tried with the following.
money = Money.new(100, from_currency)
Then I got the same error as before. But if I tried:
money = Money.new(0, from_currency)
It seems to work. I find that a bit strange.
Update
Here is the backtrace from when I try to save the record:
["/Users/[user]/.rvm/gems/ruby-2.5.1/gems/money-6.11.3/lib/money/money/arithmetic.rb:70:in =='", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/numericality.rb:22:in!='", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/numericality.rb:22:in validate_each'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:150:inblock in validate'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:147:in each'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:147:invalidate'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:413:in block in make_lambda'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:197:inblock (2 levels) in halting'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:601:in block (2 levels) in default_terminator'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:600:incatch'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:600:in block in default_terminator'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:198:inblock in halting'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:in block in invoke_before'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:ineach'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:in invoke_before'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:130:inrun_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:827:in _run_validate_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations.rb:405:inrun_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/callbacks.rb:114:in block in run_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:97:inrun_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:827:in _run_validation_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/callbacks.rb:114:inrun_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations.rb:335:in valid?'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:65:invalid?'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:82:in perform_validations'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:50:insave!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/attribute_methods/dirty.rb:43:in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:313:inblock in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:384:in block in with_transaction_returning_status'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/database_statements.rb:235:inblock in transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/transaction.rb:194:in block in within_new_transaction'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/monitor.rb:226:inmon_synchronize'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/transaction.rb:191:in within_new_transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/database_statements.rb:235:intransaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:210:in transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:381:inwith_transaction_returning_status'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:313:in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/suppressor.rb:46:insave!'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:245:in block in set_supported_currencys_for_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:240:ineach'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:240:in set_supported_currencys_for_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:224:inset_up_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:208:in match_product_variant_to_product'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:84:inblock in get_products_from_api_data'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:75:in map'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:75:inget_products_from_api_data'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:25:in import'", "(irb):2:inirb_binding'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in eval'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:inevaluate'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/context.rb:380:in evaluate'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:491:inblock (2 levels) in eval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:623:in signal_status'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:488:inblock in eval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:246:in block (2 levels) in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:232:inloop'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:232:in block in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:231:incatch'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:231:in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:487:ineval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:428:in block in run'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:427:incatch'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:427:in run'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:383:instart'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:62:in start'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:17:instart'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:97:in perform'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor/command.rb:27:inrun'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor/invocation.rb:126:in invoke_command'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor.rb:387:indispatch'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/command/base.rb:63:in perform'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/command.rb:44:ininvoke'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands.rb:16:in <top (required)>'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:inrequire'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in block in require'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:inload_dependency'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in require'", "/Users/[user]/Documents/Development/wondery/[appname]/bin/rails:9:in'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:in load'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:inblock in load'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:in load_dependency'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:inload'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in require'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:inrequire'", "-e:1:in `'"]
The error comes from a numericality validation on your model.
Money gem does not allow to compare a money object with a Number, unless thee number is zero. Otherwise it expects you to compare Money with Money.
In irb you can try:
```ruby
2.5.1 :006 > Money.new(1000, "USD") != Money.new(1000, "USD")
=> false
2.5.1 :007 > Money.new(1000, "USD") != 1000
Traceback (most recent call last):
4: from /Users/andi/.rvm/rubies/ruby-2.5.1/bin/irb:11:in `<main>'
3: from (irb):7
2: from (irb):7:in `!='
1: from /Users/andi/.rvm/gems/ruby-2.5.1/gems/money-6.12.0/lib/money/money/arithmetic.rb:70:in `=='
ArgumentError (Money#== supports only zero numerics)
2.5.1 :008 > Money.new(1000, "USD") != 0
=> true
```
I believe that this error makes sense, as you can't really compare an arbitrary number with an amount of money in a given currency.
The money-rails gem again comes with it's own validators:
https://github.com/RubyMoney/money-rails#numericality-validation-options
Your backtrace shows that you are using the rails numericality validator instead.
You might also come across this error when you are writing specs:
expect(order.subtotal).to eq 123.45
# ArgumentError:
# Money#== supports only zero numerics
expect(order.subtotal).to eq Money.new(12345)
# works!
Money Rails automatically adds "_cents" to the attribute you are monetizing. Then it creates an instance of that model.price which includes
<Money fractional:1500 currency:DKK>
Hence, you cannot do model.price + 10 as it would cause the error you are getting.
You may therefore want to monetize price_to_convert, or any other value you are working with so that you can sum them up, etc.
Create a new migration file e.g.
rails g migration AddMoneytizeToOrders
change migration file so that it reads as follow (change column/attribute to your values)
class AddMonetizeToOrder < ActiveRecord::Migration[6.0]
def change
add_monetize :orders, :price_to_convert, currency: { present: false }
end
end
In your model you must include
monetize :price_to_convert_cents
then you can work with e.g.(rails c) Order.last.price_to_convert + Model.last.price, etc.
Please note that you cannot use self.[:price_to_convert] as money rails wouldn't understand it and you would get the error
money rails ActiveModel::MissingAttributeError (can't write unknown attribute...
Therefore use self.price_to_convert instead

NoMemoryError: failed to allocate memory - Ruby on Rails

I generated a simple script that on other occasions has worked for me, but this is because the amount of information in the loop generates a NoMemoryError error.
I have 16 GB of memory and also a lot of virtual memory available. When I perform the test, the RAM memory is completely filled.
The script is:
require 'rest-client'
require 'json'
require 'open-uri'
require 'csv'
def self.qos7705egressdiscard_summary
xml = File.read("#{Rails.root}/public/Discard_qos7705egress.xml")
data = RestClient.post("http://10.140.255.1:8080/xmlapi/invoke", xml,{:"Content-Type" => 'application/soap+xml'})
data_parsed = Hash.from_xml(data)
return data_parsed
end
def self.samqos7705egressdiscardtotal_table
tabletotal = Hash.new
data_stats = qos7705egressdiscard_summary['Envelope']['Body']['findResponse']['result']['service.SapEgrQosQueueStatsLogRecord']
data_stats.map do |qosdiscard_device|
#devicetotal = qosdiscard_device["monitoredObjectSiteName"]
#servicetotal = qosdiscard_device["monitoredObjectPointer"]
#porttotal = qosdiscard_device["displayedName"]
#queueIdtotal = qosdiscard_device["queueId"]
#discardinproftotal = qosdiscard_device["droppedInProfOctets"].to_i
#discardoutproftotal = qosdiscard_device["droppedOutProfOctets"].to_i
time_unixtotal = (qosdiscard_device["timeCaptured"]).to_i/1000
#timeCapturedtotal = Time.at(time_unixtotal).strftime("%B %e, %Y at %I:%M %p")
#discardtotal = #discardinproftotal + #discardoutproftotal
#device_int_stats_total = (#devicetotal+#porttotal+#queueIdtotal).to_s
hash = Hash[devicetotal: #devicetotal, servicetotal: #servicetotal, porttotal: #porttotal, queueIdtotal: #queueIdtotal, discardtotal: #discardtotal, device_int_stats_total: #device_int_stats_total, timeCapturedtotal: #timeCapturedtotal, time_unixtotal: time_unixtotal]
tabletotal << hash
#tabletotal.write(hash)
end
end
The exact error is:
NoMemoryError: failed to allocate memory
from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:108:in `inspect'
from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:108:in `block in <module:IRB>'
from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:101:in `call'
from /usr/local/lib/ruby/2.2.0/irb/inspector.rb:101:in `inspect_value'
from /usr/local/lib/ruby/2.2.0/irb/context.rb:383:in `inspect_last_value'
from /usr/local/lib/ruby/2.2.0/irb.rb:661:in `output_value'
from /usr/local/lib/ruby/2.2.0/irb.rb:490:in `block (2 levels) in eval_input'
from /usr/local/lib/ruby/2.2.0/irb.rb:623:in `signal_status'
from /usr/local/lib/ruby/2.2.0/irb.rb:486:in `block in eval_input'
from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:245:in `block (2 levels) in each_top_level_statement'
from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:231:in `loop'
from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:231:in `block in each_top_level_statement'
from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:230:in `catch'
from /usr/local/lib/ruby/2.2.0/irb/ruby-lex.rb:230:in `each_top_level_statement'
from /usr/local/lib/ruby/2.2.0/irb.rb:485:in `eval_input'
from /usr/local/lib/ruby/2.2.0/irb.rb:395:in `block in start'
from /usr/local/lib/ruby/2.2.0/irb.rb:394:in `catch'
from /usr/local/lib/ruby/2.2.0/irb.rb:394:in `start'
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /usr/local/lib/ruby/gems/2.2.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'Maybe IRB bug!
On line 25 I added this tabletotal.write (hash) to be able to write it on disk and not in memory but I got the following error:
NoMethodError: undefined method `write' for {}:Hash
What is the problem here? Also how can I fix it?
Start by making it less cr*p:
def extract_data(input)
{
devicetotal: input["monitoredObjectSiteName"],
servicetotal: input["monitoredObjectPointer"],
porttotal: input["displayedName"],
queueIdtotal: input["queueId"],
discardinproftotal: input["droppedInProfOctets"].to_i,
discardoutproftotal: input["droppedOutProfOctets"].to_i,
time_unixtotal: input["timeCaptured"].to_i/1000
}.tap do |h|
h[:timeCapturedtotal] = Time.at(h[:time_unixtotal]).strftime("%B %e, %Y at %I:%M %p"),
h[:discardtotal] = h[:discardinproftotal] + h[:discardoutproftotal]
h[:device_int_stats_total] =(h[:devicetotal]+h[:porttotal]+h[:queueIdtotal]).to_s
end
end
This method is really easy to test since you just insert input and write assertions about the output.
If you want to map and apply this to the input array you would do:
data_stats.map(&:extract_data)
Your code tries to output a hash but uses the shovel operator like on a array. You need to decide if the appropiate output is an array or a hash.
I need all those variables because I use them in a html in table
format.
This won't work - the instance variables will only contain the values from the last element as they get overwritten in each iteration.
You instead need to iterate over an array of hashes or objects in the view:
<% #stats.each do |s| %>
<tr>
<td><%= s[:devicetotal] %></td>
# ...
</tr>
<% end %>
If you really want to use instance varibles you need to create a object instance for each element:
class DataStat
include ActiveModel::AttributeAssignment
attr_accessor :devicetotal, :servicetotal # ...
def self.from_import(input)
self.new(
devicetotal: input["monitoredObjectSiteName"],
servicetotal: input["monitoredObjectPointer"],
# ...
)
end
end
#stats = data_stats.map { |ds| DataStat.from_import(ds) }
You also need to deal with the issue that you´re running out of memory since you are just slop converting the whole XML document into a Ruby hash. You need to parse it with Nokogiri instead and extract what you actually need.

Active Record acting weird

Question am I doing something wrong with the following code?
Controller Test
irb(main):003:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.8ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation]'
=> #<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
The above works and retrieves my row that I queried for.
but below I tried to get the data for x.owner_id from the above and it fails(which clearly owner_id is a column in the returned query above)
irb(main):005:0> x.owner_id
NoMethodError: undefined method `owner_id' for #<Notations::ActiveRecord_Relation:0x007fb83cecf288>
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:136:in `method_missing'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:99:in `method_missing'
from (irb):5
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:110:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:9:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
I found the problem. The column names of the db were uppercase, so:
y = x.owner_id # failure
y = x.OWNER_ID # success
irb(main):004:0> x.OWNER_ID
=> "00003"
Solution:
Using an initializer to use lowercase schema reflection:
ActiveRecord::ConnectionAdapters::SQLServerAdapter.lowercase_schema_reflection = true
So now:
x = Notations.all.first
irb(main):002:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.9ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation] ORDER BY [notation].[owner_id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'
irb(main):003:0> x.owner_id
=> "00003"
irb(main):004:0>
As you can see above adding the initializer worked it changed the columns to lower case. I agree with having my columns lower case in the first place. However I am unable to change them due to this DB is used with my company's ERP system
You are calling the attribute on ActiveRecord::Relation whereas you must be calling it on Notations instance
x = Notations.all
#<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
notation = x.first
#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">
notation.owner_id
#=> "00003"
NOTE: Whereas the above code must be working for you I will suggest few changes as per the ruby standard
Model name must be singular Notation instead of Notations
column names must be in lowercase owner_id instead of OWNER_ID

Ruby Newbie strftime Time.Now

I have the following written in ruby
t = Time.now
t.strftime("%Y-%d-%m")
SCHEDULER.every '1m', :first_in => 0 do |job|
send_event('gmail_gh', {current: gmail.inbox.count(:after => Date.parse(t)), older: gmail.inbox.count})
But i get this error
scheduler caught exception:
can't convert Time into String
/var/dashing/cdmdash/jobs/gmail_gh.rb:21:in `parse'
/var/dashing/cdmdash/jobs/gmail_gh.rb:21:in `block in <top (required)>'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:231:in `call'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:231:in `trigger_block'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:191:in `block in trigger'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/scheduler.rb:416:in `call'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/scheduler.rb:416:in `block in trigger_job'
I think it has something to do with the t variable and it not being a truing, I am new to Ruby so I am abit stuck
If you look at the gem documentation, you will see that the :after and :before params take in a date in the format of YYYY-MM-DD.
From the gem Readme:
gmail.inbox.count(:after => Date.parse("2010-02-20"), :before => Date.parse("2010-03-20"))
gmail.inbox.count(:on => Date.parse("2010-04-15"))
Your code is passing in YYYY-DD-MM which is likely causing the error.
Edit
When you call strftime on a datetime object, it doesn't modify the object - only returns the string notation based on format you give.
As a result, the Date.parse(t) is still getting Time.now was a parameter.
Try this:
t = Time.now.strftime("%Y-%m-%d")
Date.parse(t)

Using Time of Day In Conditions of find while Ignoring Calendar Date with Rails

I want to create a query that will return all Alerts that have a start time before "right now" and an end time after "right now", and I only care about what time of day it is, not what date it is.
I would have thought this would work
Alert.find(:all, :conditions => [" ? between ? AND ?", Time.now, :start, :end])
However it does not because this query concerns itself with calendar dates, not just time of day.
I found ".to_s(:time)" but when I add that I get an error.
Alert.find(:all, :conditions => [" ? between ? AND ?", Time.now.to_s(:time), :start.to_s(:time), :end.to_s(:time)])
Alert.find(:all, :conditions => [" ? between ? AND ?", Time.now.to_s(:time), :start.to_s(:time), :end.to_s(:time)])
ArgumentError: wrong number of arguments(1 for 0)
from (irb):48:in `to_s'
from (irb):48
from /home/chris/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.3/lib/rails/commands/console.rb:47:in `start'
from /home/chris/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.3/lib/rails/commands/console.rb:8:in `start'
from /home/chris/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.3/lib/rails/commands.rb:41:in `'
from script/rails:6:in `require'
from script/rails:6:in `'
How can I find all the of alerts that are active right now, based on now being between the start and end time of the Alert, irrespective of the calendar date of the start and end time? I am not currently thinking about time zones but will in the future.
This question represents a bug in ActiveRecord when using sqlite. The solution to this is to switch to mysql. More info here: https://github.com/rails/rails/issues/6247#issuecomment-5679856

Resources