Undefined method `bytesize' for #<Hash> - ruby

I'd like to store and update blogger labels to datastore in GAE.
When I run that code, I get this error:
javax.servlet.ServletContext log: Application Error
/base/data/home/apps/yet-another-problem/1.334886515480009498/WEB-INF/gems/gems/sinatra-0.9.2/lib/sinatra/base.rb:45:in `each': undefined method `bytesize' for #<Hash:0x86684c> (NoMethodError)
The Code
class Labels
class LabelData
include Bumble
ds :blog_element_labels
end
def update
response = URLFetch.get($label_url)
result = response.to_s
result_headless = result.gsub("listLabels(",'')
pure_result = result_headless.gsub(");",'')
json_to_yaml = YAML::load(pure_result)['entry']['category']
json_to_yaml.each do |label|
#label = LabelData.find(:blog_element_labels => label['term'])
#label = LabelData.create(:blog_element_labels => label['term']) if #label.nil?
end
end
end
and run by cron job does '/job'
get '/job' do
#labels = Labels.new
#labels.update
end
Where is the problem? Please teach me.
But when run cron job first time, label data was stored, even occur that error.
Could not update data.

I think your having the same problem that's been discussed here: error happens when I try "all" method in datamapper
In your case, Sinatra is trying to take the return value of #lavels.update and turn that into a string to display to the user.
Try this to see if it fixes the problem:
get '/job' do
#labels = Labels.new
#labels.update
"Labels Updated"
end
Your return value is now a string, so you shouldn't get the error.

Related

Can you help me in converting an array to an index while scraping more data?

I would like to grab more data from my scraper class but im getting what seems like a simple integer conversion error.
here is the code
def get_more_info_for_aircraft
aircraft = gets.strip.to_i #sintrg to an integer to_i
UsAircraft::Scraper.more_info_for_aircraft(aircraft)
puts "AIRCRAFT INTEL FOR #{aircraft}."
UsAircraft::Aircraft.all.each.with_index(1) do |aircraft|
puts "#{aircraft.contractor} - #{aircraft.service} - #{aircraft.armament} - #{aircraft.power_plant} - #{aircraft.speed} - #{aircraft.range}"
end
end
and the error code
scraper.rb:24:in `more_info_for_aircraft': undefined method `path' for 1:Integer (NoMethodError)
heres the link to the git hub to see the scraper class. any help would be much appreciated.
https://github.com/codyalvarez/us_aircraft
The problem is here.
def self.more_info_for_aircraft(aircraft)
url = "#{BASE_URL}#{aircraft.path}"
The error is saying that instead of passing in an instance of UsAircraft::Aircraft you've passed in the Integer 1.
That's done here.
def get_more_info_for_aircraft
aircraft = gets.strip.to_i #sintrg to an integer to_i
UsAircraft::Scraper.more_info_for_aircraft(aircraft)
It doesn't matter if you did because UsAircraft::Aircraft doesn't have a path method.

How to update value of a Model's attribute in a for loop

I have the following code which works finde
twt = Tweet.where(user_id: #user.uid).where(status_id: 0).order(:created_at, :id).first
twt.status_id = 1
twt.save
I the want to make this code run for every user available in the database:
#user = User.all
#user.each do |u|
twt = Tweet.where(user_id: u.uid).where(status_id: 0).order(:created_at, :id).first
twt.status_id = 1
twt.save
end
this however gives me the error:
undefined method `status_id=' for nil:NilClass
why is there no class found? Why wasn't it set correctly in twt?
Simply, for some user, this line
twt = Tweet.where(user_id: u.uid).where(status_id: 0).order(:created_at, :id).first
found no results. You could add
if twt
twt.status_id = 1
twt.save
end
Anyway, you can rewrite that as
Tweet.find_by(user_id: u.uid, status_id: 0).order(:created_at, :id)
Obviously, it's possible to do all this job in just one SQL query.

Can't convert Configatron::Store to String error when value used as parameter to Object.const_get

I recently replaced a home-grown configuration module with Configatron, but I'm unable to get one use case working.
When I attempt to use a configatron value as an argument to Object.const_get like this:
def formatter_class
Object.const_get(configatron.formatter)
end
I get the following error:
file.rb:10:in `const_get': can't convert Configatron::Store to String
(Configatron::Store#to_str gives Configatron::Store) (TypeError)
The configatron assignment looks like this (simplified):
configatron.formatter = case
when condition?
'ExportFormat'
else
'ScreenFormat'
end
Even if I do configatron.formatter = 'ScreenFormat', I get the same error.
I've tried variations on the formatter_class method too. This fails:
def formatter_class
Object.const_get(configatron['formatter'])
end
Of course, this succeeds, but won't fulfill my use case:
def formatter_class
Object.const_get('ScreenFormat')
end
What am I doing wrong?
I solved my issue. Turns out you can call configatron.whatever and it will return a Configatron::Store if it's not initialized.
I inserted a call to configatron.has_key? 'formatter' before accessing the value. When it returned false, I figured out that the error was occurring in a code path where the value hadn't been initialized yet. Once I initialized the value, the error no longer occurs.
Happens when .yml config file is missing. Or the key that you are looking for is not there.
Location:
/config/NAME.yml

how to use rspec to mock a class method inside a module

Im trying to test a create method that has a call to an external API but I'm having trouble mocking the external API request. Heres my setup and what I've tried so far:
class Update
def self.create(properties)
update = Update.new(properties)
begin
my_file = StoreClient::File.get(properties["id"])
update.filename = my_file.filename
rescue
update.filename = ""
end
update.save
end
end
context "Store request fails" do
it "sets a blank filename" do
store_double = double("StoreClient::File")
store_double.should_receive(:get).with(an_instance_of(Hash)).and_throw(:sad)
update = Update.create({ "id" => "222" })
update.filename.should eq ""
end
end
at the moment Im getting this failure
Failure/Error: store_double.should_receive(:get).with(an_instance_of(Hash)).and_throw(:sad)
(Double "StoreClient::File").get(#<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x000001037a9208 #klass=Hash>)
expected: 1 time
received: 0 times
why is my double not working and how is best to mock the call to StoreClient::File.get, so that I can test the create method when it succeeds or fails?
The problem is that double("StoreClient::File") creates a double called "StoreClient::File", it does not actually substitute itself for the real StoreClient::File object.
In your case I don't think you actually need a double. You can stub the get method on the StoreClient::File object directly as follows:
context "Store request fails" do
it "sets a blank filename" do
StoreClient::File.should_receive(:get).with(an_instance_of(Hash)).and_throw(:sad)
update = Update.create({ "id" => "222" })
update.filename.should eq ""
end
end

How do I handle the wrong number of method arguments?

I'm working on a URL shortener and attemtping to convert the URL ID, which is a number, into a string, using base 36.
I'm receiving the error listed below the code:
def self.create_link(original)
url = Url.create(:original => original)
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
link.url = url
link.save
return link
else
create_link(original)
end
end
I'm receiving the following error:
wrong number of arguments(1 for 0) file: tinyclone.rb location: to_s line: 91
When I researched the error, I found someone who mentioned that this error is common when you attempt to pass in parameter values when a method doesn't accept them. The error is specifically referring the following line.
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
What's the type of url.id?
I think your expecting it to be a FixNum whose to_s method accepts a radix, but you're getting something else instead... maybe a string containing a number? (e.g. "1234")
Anyway, the method seems to require no arguments and you are passing 36 nevertheless
EDIT:
Can't find the reference to the class you pointed out (Serial), but this might be worth a try:
url.id.to_i.to_s(36)
One thing I see right away is:
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
Notice that in the first line you have :indentifier and in the second it's :identifier.
Otherwise, I agree with #Pablo Fernandez's answer that it's probably tied to the type of id.
you have 2 models, but take full responsibility on the one of them only. please take a look at code separated logic:
# Link model
def self.create_link(original)
url = Url.create(:original => original)
url_id = url.encoded_id
find_or_create_by_identifier!(:identifier => url_id)
end
# Url model
def before_validate_on_create
if url.id.to_s.include? DIRTY_WORDS
self.errors.add(:base, 'the url is invalid')
end
end
def encoded_id
url.id.to_s(36)
end

Resources