Why sidekiq returned error? - ruby-on-rails

I trying to use sidekiq in my app, but when I write this simple worker
class ParseWorker
include Sidekiq::Worker
def perform(instance)
instance.spideys << Spidey.create
end
end
and I use this worker here
def create
#user_link = UserLink.new(user_link_params)
if #user_link.save
binding.pry
ParseWorker.perform_async(#user_link)
redirect_to results_user_links_path
end
end
was returned the error
2015-04-09T13:14:56.757Z 11644 TID-ay1nc ERROR: Actor crashed!
NoMethodError: undefined method `spideys' for "#<UserLink:0x007f65f00d99b0>":String
/home/weare138/simple-parser/app/workers/parse_worker.rb:7:in `perform'
but why? #user_link is not a string
how fix?
upd
def perform(id)
user_link = UserLink.find(id)
user_link.spideys << Spidey.create
end
error
2015-04-09T14:15:21.889Z 11644 TID-ay1nc ERROR: Actor crashed!
NoMethodError: undefined method `spideys' for 39:Fixnum
upd2
class ParseWorker
include Sidekiq::Worker
require 'open-uri'
def perform(id)
user_link = UserLink.find(id)
user_link.spideys << Spidey.create
end
end

Sidekiq uses Redis, so when you pass to the worker an object, it serializes it to JSON.
From the Sidekiq documentation:
This means the arguments to your worker must be simple JSON datatypes
(numbers, strings, boolean, array, hash). Complex Ruby objects (e.g.
Date, Time, ActiveRecord instances) will not serialize properly.
Instead you should do
def create
...
ParseWorker.perform_async(#user_link.id)
end
def perform(id)
UserLink.find(id).spideys << Spidey.create
end

Related

Rails does not recognize model method

I have a method on my model and it actually was created as advised(with self.method_name). However, when I go to my console and try to test the method I get an undefined method error.
Does anyone know why?
my Model
class Country < ApplicationRecord
has_many :facts
has_many :dishes
has_many :touristic_places
include HTTParty
base_uri 'restcountries.eu/rest/v2/region/africa'
def self.save_data_from_api
response = HTTParty.get(base_uri)
country_data = JSON.parse(response)
countries = country_data.map do |line|
c = Country.new
c.name = line.name
c.save
c
end
countries.select(&:persisted?)
end
On my Controller
def save_data_from_api
countrie = Country.save_data_from_api
end
Test on Rails console error:
> Country.save_data_from_api
Traceback (most recent call last):
2: from (irb):5
1: from (irb):5:in `rescue in irb_binding'
NoMethodError (undefined method `save_data_from_api' for #<Class:0x00007fc9ec71edd8>)
Don't do HTTP calls in your model. Even without any code your model already has a ton of responsibilities that it gets from ActiveRecord::Base:
validations
assocations
persistence
callbacks
naming
i18n
Instead create a separate client object that fetches the data from the API. This gives you an object which just does one job which is both easy to test and stub out:
# app/clients/rest_countries_client.rb
# HTTP client for the restcountries.eu API
class RestCountriesClient
include HTTParty
base_uri 'restcountries.eu/rest/v2'
format :json # this will automatically parse the response
def self.region(region)
get("/region/#{region}")
end
end
This lets you just test the API call from the console by calling RestCountriesClient.region('africa') and you can see the returned hash without any side-effects.
To actually do the call and persist the objects you want to use a service object or ActiveJob:
# app/jobs/country_importer_job.rb
# Persists countries from the restcountries.eu API
class CountryImporterJob < ApplicationJob
def perform(region = 'africa')
response = RestCountriesClient.region(region)
return unless response.success?
response.map do |line|
Country.create(name: line["name"])
end.select(&:persisted?)
end
end
You would then call this job from the controller:
CountryImporterJob.perform_now('africa')
Quit the console and start it again. Auto-reload only works in the server, not the console.

Uninitialized constant CreateJob::RestClient

I am trying to get a job to fire off that creates an order in our ERP.
all works just fine directly through the gem, so I started making the job itself.
I have 3 files: erp_order_methods.rb, create_or_update_erp_order.rb order.rb
erp_order_methods.rb:
module ErpOrderMethods
# These methods are used by create_or_update_erp_order_job
def self.include base
bese.extend ClassMethods
end
module ClassMethods
create_or_update_erp_order_job.rb
class CreateOrUpdateErpOrderJob
include ErpOrderMethods
#queue = :priority_queue
def self.perform(task_id, order_id)
task = Task.find(task_id)
order = Order.find(order_id)
erp_order = order.erp_order
order.rb (model)
def create_or_update_erp_order
#task = Task.create(
status: "scheduled",
description: "Create or Updat Order for Web Order No: #{self.id}",
system_task: true
)
Resque.enqueue(CreateOrUpdateErpOrderJob, #task.id, self.id)
end
When i go to test this, I am getting:
General Error: Type - NameError | Message - uninitialized constant CreateOrUpdateErpOrderJob::RestClient
so I found the issue after some digging around.
def self.include base
bese.extend ClassMethods
spelling errors: bese => base
self.include => self.included

Ruby undefined method each

i am new to ruby language and i tried to learn it now.
i have a classCompany with method find_applicants
class Company
attr_accessor :jobs
## TODO: This method should update the `jobs` property to an array of instances of
## class `Job`
def initialize(jobs)
# Load the json file and loop over the jobs to create an array of instance of `Job`
# Assign the `jobs` instance variable.
#jobs = jobs
end
## TODO: Impelement this method to return applicants from all jobs with a
## tag matching this keyword
def find_applicants(keyword)
# Use the `jobs` instance variable.
applicants = []
#jobs.each do |job|
job.applicants.each do |applicant|
applicant.tags.each do |tag|
if keyword.eql? tag
# ...
end
end
end
end
end
and the main.rb
require './src/company.rb'
require './src/applicant.rb'
require './src/job.rb'
require 'json'
company = Company.new('data/boundless.json')
applicants = company.find_applicants('google')
puts applicants
and when compile this i have this error
/Users/user/Desktop/BoundlessCaseStudy/src/company.rb:34:in find_applicants': undefined methodeach' for nil:NilClass (NoMethodError)
from main.rb:11:in `'
please help
Looks like you are passing the name of the json file where the jobs are, instead an array of jobs
company = Company.new('data/boundless.json')
but you did no wrote que code that parse this file, as the comment correctly says you should
# Load the json file and loop over the jobs to create an array of instance of `Job`,
So the variable #jobs is receiving a string, and you will get this error:
NoMethodError: undefined method `each' for "data/boundless.json":String
write the code to parse the file and set the #jobs variable correctly

How to send an option hash to sidekiq/activejob?

I'm trying to send options to a sidekiq worker. Sidekiq is using Activejob
class User
def do_background_task(object, options={})
MyJob.perform_later(id, object.id, options )
end
end
class MyJob < ActiveJob::Base
queue_as :default
def perform(user_id,object_id,options={})
user = User.find(user_id)
object = Object.find(user_id)
selector = options[:selector] if options[:type]
do some things....
if selector == 'true'
do some other things.....
end
end
end
This is not working, and seems to be because either ActiveJob or Sidekiq does not like to receive a keyed hash. So e.g., #user.do_background_task(#object, selector: true) causes an error NoMethodError: undefined method '[]' for nil:NilClass.
What is the accepted way to pass keys to a queue?

Sidekiq undefined method for string

Here is what I'm calling:
UpdateRatingAndCountWorker.perform_async(133)
Here is my worker:
# app/workers/update_rating_and_count_worker.rb
class UpdateRatingAndCountWorker
include Sidekiq::Worker
def perform(review_id)
review = Review.find(review_id.to_i)
review.style.update_average_rating!
end
end
Here is the error:
"NoMethodError: undefined method `style' for \"#<Review:0x00000005bef438>\":String"
In the error message it looks like the variable review.style is of the type String.
Since you haven't posted the code for the model Review I can only guess but, should it be
# app/workers/update_rating_and_count_worker.rb
class UpdateRatingAndCountWorker
include Sidekiq::Worker
def perform(review_id)
review = Review.find(review_id.to_i)
review.update_average_rating!
end
end
Restart Sidekiq works for me, it picks up new method in my model

Resources