NoMemoryError: failed to allocate memory - Ruby on Rails - 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.

Related

RSS Feed Entries - Encoding::CompatibilityError incompatible character encodings: ASCII-8BIT and UTF-8

I am currently working on an RSS feed that was working for a while but now has an encoding issue. After trying many of the solutions here unsuccessfully, I have deduced that I may be having issues with the feed parser.
The error starts with the index page:
ActionView::Template::Error (incompatible character encodings: ASCII-8BIT and UTF-8):
11:
12: <div class="entry_wrapper">
13: <div class="entry_box">
14: <% feed.entries.each do |entry| %>
15: <p class="entry_title"><%= sanitize link_to entry.title, entry.url %></p>
16:
17:
app/models/feed.rb:6:in `entries'
app/views/feeds/index.html.erb:14:in `block in _app_views_feeds_index_html_erb__2672739530113604393_70126099705280'
app/views/feeds/index.html.erb:5:in `_app_views_feeds_index_html_erb__2672739530113604393_70126099705280'
Here is larger section of the Feed#Index page:
<% #feeds.each do |feed| %> # Line 5 here
<p class="feed_url">
<%= link_to feed.url, feed %>
<%= link_to "Edit", edit_feed_path(feed), class: "blue" %>
<%= link_to "Delete", feed_path(feed), method: :delete, data: { confirm: 'Are you sure you want to delete this feed url?' }, class: "blue" %>
</p>
<div class="entry_wrapper">
<div class="entry_box">
<% feed.entries.each do |entry| %>
<p class="entry_title"><%= sanitize link_to entry.title, entry.url %></p>
I deleted the Feed URL's in the console so the page rendered fine without any urls to pull from. However, as soon as I added one, I got the same error as before.
I tried testing the encoding of the Feed entries in the console and got the following error:
2.1.1 :001 > g = Feed.last
Feed Load (0.1ms) SELECT "feeds".* FROM "feeds" ORDER BY "feeds"."id" DESC LIMIT 1
=> #<Feed id: 9, name: nil, created_at: "2016-01-18 05:01:54", updated_at: "2016-01-18 05:01:54", url: "http://feeds.feedburner.com/MattsTravelSite">
2.1.1 :002 > g.entries
Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and UTF-8
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/entities.rb:77:in `gsub'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/entities.rb:77:in `decode'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/entity_decoder.rb:14:in `decode'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/entity_decoder.rb:5:in `try_decode'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/sax_parser.rb:151:in `on_text'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/parser.rb:541:in `_rule_33'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/parser.rb:239:in `block in each_token'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:237:in `call'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:237:in `add_token'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:439:in `on_element_end'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:190:in `advance_native'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:190:in `block in advance'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:137:in `read_data'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/lexer.rb:189:in `advance'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/parser.rb:236:in `each_token'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/oga-2.0.0/lib/oga/xml/parser.rb:269:in `parse'
... 20 levels...
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:241:in `load'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:241:in `block in load'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:232:in `load_dependency'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:241:in `load'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/commands/rails.rb:6:in `call'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/command_wrapper.rb:38:in `call'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:183:in `block in serve'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:156:in `fork'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:156:in `serve'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:131:in `block in run'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:125:in `loop'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application.rb:125:in `run'
from /Users/danieluribe/.rvm/gems/ruby-2.1.1/gems/spring-1.3.6/lib/spring/application/boot.rb:18:in `<top (required)>'
from /Users/danieluribe/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
from /Users/danieluribe/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
I double-checked to see if the website I am pulling from is in UTF-8 encoding at the W3C-Validator website:
This document was successfully checked as well-formed XML!
Result: Passed, 1 warning(s)
Address:
http://feeds.feedburner.com/MattsTravelSite
Encoding: utf-8
Doctype: XML
Root Element: feed
Root Namespace: http://www.w3.org/2005/Atom
I tried "forcing" the encoding in the model, but I think my coding skills are a little lacking in terms of creating methods. Here is the entries model I created originally for the Feed that is being used in the Feed#Index.
class Feed < ActiveRecord::Base
has_many :items
def entries(num = 3)
Feedjira::Feed.add_common_feed_entry_element("img")
feed = Feedjira::Feed.fetch_and_parse(url)
feed.entries.take(num)
# add_items(feed.entries) # Saving items to database
end
....
Since this model was working before, I'm not sure what happened. I did take a few months from the app so I don't know if anything changed with Feedjirra. Any help would be greatly appreciated.

Can't set timezone using abbreviation

I can't set timezone on Rails using its abbreviation, for example:
>> Time.zone = 'BRT'
ArgumentError: Invalid Timezone: BRT
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:61:in `rescue in find_zone!'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:53:in `find_zone!'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-3.2.21/lib/active_support/core_ext/time/zones.rb:37:in `zone='
from (irb):14
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:47:in `start'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands/console.rb:8:in `start'
from /home/braulio/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-3.2.21/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
This is necessary as some systems (android and some browsers) report timezone using the abbreviation.
The list of abbreviations can be found at http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
jstimezone was reporting timezone using abbreviations. It is also quite buggy and unmaintained (https://bitbucket.org/pellepim/jstimezonedetect/issues?status=new&status=open). It is simpler to just use standard javascript:
var offset = - new Date().getTimezoneOffset()/60
Then call on document ready:
$.cookie("browser.tzoffset", offset, { expires: 30, path: '/' })
Then in rails use around_filter in ApplicationController:
def set_time_zone
return yield unless (utc_offset = cookies['browser.tzoffset']).present?
utc_offset = utc_offset.to_i
gmt_offset = if utc_offset == 0 then nil elsif utc_offset > 0 then -utc_offset else "+#{-utc_offset}" end
Time.use_zone("Etc/GMT#{gmt_offset}"){ yield }
rescue ArgumentError
yield
end
This localizes all dates for users, independently where he/she is. In Brazil we have multiple timezones, for example.
PS: ActiveSupport::TimeZone[utc_offset.to_i] can't be used as it uses DST, see https://github.com/rails/rails/issues/20504
PS: You can also use moment: moment.parseZone(Date.now()).utcOffset()/60 or moment().format('zz')
You don't have to use around_filter.
Put this in before_action
Time.zone = "Etc/GMT#{gmt_offset}"
(Time.zone is thread local. It's safe to change.)

Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8 (SFTP)

Using the Net-SFTP gem, Ruby 2 and Rails 4
I wrote code that was working in pure ruby, but copied my code over to rails and now I get:
Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8
What can I change in my code to get this working?
def self.get_recent_file(ftp_file, local_file)
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_file)
end
end
Log
Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `on_read'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `call'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `respond_to'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:948:in `dispatch_request'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:911:in `when_channel_polled'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `call'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `block in preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `each'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
... 13 levels...
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:802:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:787:in `connect!'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp.rb:32:in `start'
Code referenced in log from GEM:
https://github.com/net-ssh/net-sftp/blob/master/lib/net/sftp/operations/download.rb#L339
# Called when a read from a file finishes. If the read was successful
# and returned data, this will call #download_next_chunk to read the
# next bit from the file. Otherwise the file will be closed.
def on_read(response)
entry = response.request[:entry]
if response.eof?
update_progress(:close, entry)
entry.sink.close
request = sftp.close(entry.handle, &method(:on_close))
request[:entry] = entry
elsif !response.ok?
raise "read #{entry.remote}: #{response}"
else
entry.offset += response[:data].bytesize
update_progress(:get, entry, response.request[:offset], response[:data])
entry.sink.write(response[:data]) # <~~ Line#339
download_next_chunk(entry)
end
end
This helps me:
def self.get_recent_file(ftp_file, local_file)
local_io = File.new(local_file, mode: 'w', encoding: 'ASCII-8BIT')
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_io)
end
local_io.close
end
A combination of user72136's answer and the answer to this question worked for me (my remote file wasn't even ASCII):
def self.get_recent_file(ftp_file, local_file)
local_io = File.new(local_file, mode: 'wb')
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_io)
end
local_io.close
end
As line#339 is showing
entry.sink.write(response[:data])
Fix it as :
entry.sink.write(response[:data].force_encoding('ASCII-8BIT').encode('UTF-8'))
Change the line -
sftp.download!(ftp_file, local_file)
to say
sftp.download!(ftp_file, local_file).to_s.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})
This problem is being produced by how Ruby opens text-files by default after Ruby 2.0 version with UTF-8 encoding. Where you open your file you can put:
local_file = Tempfile.new(encoding: 'ascii-8bit')
#or another thing to do is to switch to binary-mode
local_file = Tempfile.new
local_file.binmode
You can also open a binary-file like this:
local_file = File.open('/tmp/local_file', 'wb')
Another solution you can do is to pass to the gem-code the filepath, instead of an open file:
def self.get_recent_file(ftp_file, local_file)
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_file.path)
end
end

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)

Nokogiri XML Builder error -> "Document already has a root node"

In my code I'm building an XML request. However, this simple fragment generates an error:
def create_gateways_request
#request_xml = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.gateways(:ua => "#{#plugin_name} #{#version}") {
xml.merchant {
xml.account MSP['merchant']['account_id']
xml.site_id MSP['merchant']['site_id']
xml.site_secure_code MSP['merchant']['site_code']
}
xml.customer {
xml.country #customer[:country]
}
}
end
#request_xml.to_xml
end
The error:
RuntimeError: Document already has a root node
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/document.rb:212:in `add_child'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:549:in `parent='
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/builder.rb:371:in `insert'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/builder.rb:363:in `method_missing'
from (irb):146
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands/console.rb:45:in `start'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands/console.rb:8:in `start'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
The root node is <gateways>, right?
What am I doing wrong here?
I cannot reproduce this locally, but you might try this at the end of your method instead:
#request_xml.doc.to_xml
It appears that it thought that you were trying to add a new <to_xml> node to the root of the document, and is complaining because you already have a <gateways> element at the root. I cannot fathom why Nokogiri 1.5.2 would do this, however, as Builder does have a to_xml method.
Here's my simple test that works for me:
require "nokogiri"
def do_it
#builder = Nokogiri::XML::Builder.new{ |x| x.root{ x.kid } }
#builder.to_xml
end
puts do_it
#=> <?xml version="1.0"?>
#=> <root>
#=> <kid/>
#=> </root>
p Nokogiri::VERSION
#=> "1.5.2"

Resources