Delayed::DeserializationError undefined method `has_key?' - ruby

I have a bug only in production. I can't reproduce the problem in development env.
I have a main class that initializes several class for process data in a background job, but this is not going well in delayed_job, here are my two classes simplified.
Handler class
class Handler
def initialize(setting)
#setting = setting
end
def process
0.upto(11) do |index|
# data = some code in local method...
launch_process(data)
end
end
protected
def launch_process(data)
Process.new(
#setting,
data: data
).boot
end
end
Process class with called by Handler class
class Process
def initialize(setting, options = {})
#setting = setting
options.each { |k,v| instance_variable_set("##{k}", v) }
end
def boot
self.delay.launch_retrieve
end
end
But when the process class is executed, I have a error by delayed_job : Delayed::DeserializationError: Job failed to load: undefined method has_key? for nil:NilClass. I don't understand why initialize of class returned this error.
Any idea ?
Thanks

Sometimes when we upgrade libs delayed jobs still keep old references.
Try to find the id of delayed_job in logs and play to parse its handler to ruby to find the wrong reference
j = DelayedJob.find(XXX)
data = YAML.load_dj(j.handler)
data.to_ruby
I made a pull request to help with this problem.
Meanwhile you can use this lines
# config/initializers/delayed_job.rb
# Monkey patch to use old class references
module Psych
class << self; attr_accessor :old_class_references end
#old_class_references = {}
class ClassLoader
private
def find klassname
klassname = ::Psych.old_class_references[klassname] || klassname
#cache[klassname] ||= resolve(klassname)
end
end
module Visitors
class ToRuby < Psych::Visitors::Visitor
def revive klass, node
if klass.is_a? String
klassname = ::Psych.old_class_references[klass] || klass
klass = Kernel.const_get(klassname) rescue klassname
end
s = register(node, klass.allocate)
init_with(s, revive_hash({}, node), node)
end
end
end
end
# Add all old dependencies (hash keys) pointing to new references (hash values)
Psych.old_class_references = {
'ActiveRecord::AttributeSet' => 'ActiveModel::AttributeSet'
# ...
}

Related

How should I call object methods from a static method in a ruby class?

From an academic / "for interests sake" (best practice) perspective:
In a Ruby class, I want to provide a static method that calls instance methods of the class. Is this considered an acceptable way of doing it, or is there is a "better" way?
class MyUtil
def apiClient
#apiClient ||= begin
apiClient = Vendor::API::Client.new("mykey")
end
end
def self.setUpSomething(param1, param2, param3=nil)
util = self.new() # <-- is this ok?
util.apiClient.call("foo", param2)
# some logic and more util.apiClient.calls() re-use client.
end
end
And then I can use this lib easily:
MyUtil.setUpSomething("yes","blue")
vs
MyUtil.new().setupUpSomething()
# or
util = MyUtil.new()
util.setUpSomething()
The environment is sys admin scripts that get executed in a controlled manner, 1 call at a time (i.e. not a webapp type of environment that could be subjected to high load).
Personally I would probably do something like:
class MyUtil
API_KEY = "mykey"
def apiClient
#apiClient
end
def initialize
#apiClient = Vendor::API::Client.new(API_KEY)
yield self if block_given?
end
class << self
def setUpSomthing(arg1,arg2,arg3=nil)
self.new do |util|
#setup logic goes here
end
end
def api_call(arg1,arg2,arg3)
util = setUpSomthing(arg1,arg2,arg3)
util.apiClient.call("foo", param2)
#do other stuff
end
end
end
The difference is subtle but in this version setUpSomthing guarantees a return of the instance of the class and it's more obvious what you're doing.
Here setUpSomthing is responsible for setting up the object and then returning it so it can be used for things, this way you have a clear separation of creating the object and setting the object up.
In this particular case you likely need a class instance variable:
class MyUtil
#apiClient = Vendor::API::Client.new("mykey")
def self.setUpSomething(param1, param2, param3=nil)
#apiClient.call("foo", param2)
# some logic and more util.apiClient.calls() re-use client.
end
end
If you want a lazy instantiation, use an accessor:
class MyUtil
class << self
def api_client
#apiClient ||= Vendor::API::Client.new("mykey")
end
def setUpSomething(param1, param2, param3=nil)
apiClient.call("foo", param2)
# some logic and more util.apiClient.calls() re-use client.
end
end
end
Brett, what do you think about this:
class MyUtil
API_KEY = 'SECRET'
def do_something(data)
api_client.foo(data)
end
def do_something_else(data)
api_client.foo(data)
api_client.bar(data)
end
private
def api_client
#api_client ||= Vendor::API::Client.new(API_KEY)
end
end
Usage
s = MyUtil.new
s.do_something('Example') # First call
s.do_something_else('Example 2')

How to test a class method that modifies an attribute of another class in a containerised way rspec

I have an issue I have been whacking my head against for hours now, and neither I nor anyone I have asked has been able to come up with a suitable answer.
Essentially, I am writing a method that allows me to edit an instance variable of another method. I have multiple ways of doing this, however my issue is with writing the test for this method. I have tried many different double types, however as they are immutable and do not store states, I did not manage to find a way to make it work.
Here is the class whose working variable is changed:
class MyClass
attr_writer :working
def working?
#working
end
end
Here is the class and method that change it:
class OtherClass
def makes_work
#ary_of_instances_of_MyClass_to_fix.map do |x|
x.working = true
#ary_of_fixed_objects << x
end
end
end
(The actual class is much larger, but I have only included a generalised version of the method in question. I can put all of the specific code up in a gist if it would help)
So I need a way to test that makes_work does in fact accept the array of objects to be changed, changes them and appends them to array_of_fixed_objects. What would be the best way of testing this in a containerised way, without requiring MyClass?
My last attempt was using spies to see what methods were called on my dummy instance, however a range of failures, depending on what I did. Here is the most recent test I wrote:
describe '#make_work' do
it 'returns array of working instances' do
test_obj = spy('test_obj')
subject.ary_of_instances_of_MyClass_to_fix = [test_obj]
subject.makes_work
expect(test_obj).to have_received(working = true)
end
end
This currently throws the error:
undefined method to_sym for true:TrueClass
Many thanks for any help! I apologise if some formatting/ info is a little bit messed up, I am still pretty new to this whole stackoverflow thing!
I think the problem is have_received(working = true), it should be have_received(:working=).with(true)
Edit:
Examples of using have_received
https://github.com/rspec/rspec-mocks#test-spies
https://relishapp.com/rspec/rspec-mocks/v/3-5/docs/setting-constraints/matching-arguments
This works for me
class MyClass
attr_writer :working
def working?
#working
end
end
class OtherClass
attr_writer :ary_of_instances_of_MyClass_to_fix
def initialize
#ary_of_fixed_objects = []
end
def makes_work
#ary_of_instances_of_MyClass_to_fix.map do |x|
x.working = true
#ary_of_fixed_objects << x
end
end
end
describe '#make_work' do
subject { OtherClass.new }
it 'returns array of working instances' do
test_obj = spy('test_obj')
subject.ary_of_instances_of_MyClass_to_fix = [test_obj]
subject.makes_work
expect(test_obj).to have_received(:working=).with(true)
end
end
If you'd rather just avoid stubbing, you could use an instance of OpenStruct instead of a double:
class OtherClass
attr_writer :ary_of_instances_of_MyClass_to_fix
def initialize
#ary_of_instances_of_MyClass_to_fix, #ary_of_fixed_objects = [], []
end
def makes_work
#ary_of_instances_of_MyClass_to_fix.map do |x|
x.working = true
#ary_of_fixed_objects << x
end
#ary_of_fixed_objects
end
end
require 'ostruct'
RSpec.describe "#makes_work" do
describe "given an array" do
let(:array) { [OpenStruct.new(working: nil)] }
subject { OtherClass.new }
before do
subject.ary_of_instances_of_MyClass_to_fix = array
end
it "sets the 'working' attribute for each element" do
expect(array.map(&:working)).to eq [nil]
subject.makes_work
expect(array.map(&:working)).to eq [true]
end
end
end

Accessing a variable from a lower class that was NOT created as a child class (ie: using the "<" operator) in Ruby

I have a ToDo list program I'm writing for practice. My problem is that by separating concerns and making each list be a class while each task is also a class, I would like to be able to call the name of the list which the new task is being added to without having to pass the list name into the task class (either upon creation or later):
class HigherClass
def initialize
#higher_class_variable = unique_value
#instance_of_lower_class #keep variable empty for now
end
end
class LowerClass
def intitialize
#lower_class_variable = unique_value #this should be the same unique value as above
end
end
instance_of_higher_class = HigherClass.new
instance_of_higher_class.#instance_of_lower_class = LowerClass.new
instance_of_higher_class.#instance_of_lower_class.#lower_class_variable
#this should return the unique_value from the HigherClass instance
If you want to access attributes:
attr_reader :lower_class_variable
Then you can just do this:
#instance_of_lower_class.lower_class_variable
Same principle applies here for higher class:
class HigherClass
attr_writer :instance_of_lower_class
end
Then:
instance_of_higher_class.instance_of_lower_class = LowerClass.new
That all seems rather clunky considering you can do this:
class HigherClass
attr_accessor :unique
def initialize
#unique = unique_value
end
end
class LowerClass < HigherClass
def initialize
# Call superclass initialization
super
# Anything else you want here.
end
def something_using_unique
call_method(unique)
end
end

how do I create a class that stores instances?

I want something like the following but would like it to be reusable for different classes.
How do I refactor this code, so with minimal effort it can be included in a class and that class will automatically be collecting instances whenever new is called?
I've tried all sorts of things like overriding new or initialize but just can't get the magic to happen.
class Person
##people_instances = []
def initialize
##people_instances << self
end
def self.instances
##people_instances
end
end
People.new
People.new
Poople.instances
=> [#<Person:0x000001071a7e28>, #<Person:0x000001071a3828>]
After some feedback below, I don't think the answer is to put the instances in a class variable as it will stay in memory forever. Rails cache is also not so appropriate as I don't need the instances to persist.
The following code uses class instance variables instead of class variables.
http://www.dzone.com/snippets/class-variables-vs-class
class Employee
class << self; attr_accessor :instances; end
def store
self.class.instances ||= []
self.class.instances << self
end
def initialize name
#name = name
end
end
class Overhead < Employee; end
class Programmer < Employee; end
Overhead.new('Martin').store
Overhead.new('Roy').store
Programmer.new('Erik').store
puts Overhead.instances.size # => 2
puts Programmer.instances.size # => 1
Will these instance variables be unique to every rails request or will they persist?
UPDATED ANSWER
If you want to keep it available during the request alone, none of the previous answers can do it. The solution for keeping it available only during the request-response cycle is to use a thread-local that is assigned in a controller method, example:
class YourController < ApplicationController
around_filter :cache_objects
protected
def cache_objects
Thread.current[:my_objects] = ['my-object', 'my-other-object']
yield
ensure
Thread.current[:my_objects]
end
end
Then, at the code that needs it, you just do Thread.current[:my_objects] and do whatever you would like to do with them. You need to use an around_filter because your web framework or server structure could try to reuse threads and the only real solution is to clean them up once the request is done to avoid memory leaks.
OLD ANSWER
Not sure what you're trying to do, but you can easily pick every single instance of a class using ObjectSpace:
ObjectSpace.each_object(String) { |s| puts(s) }
If what you need is as a database cache just use the Rails cache, load these objects once and then keep them in the cache. When using the Rails cache all you need to do is send your objects to the cache:
Rails.cache.write( "my_cached_objects", [ 'first-object', 'second-object' ] )
And then get them somewhere else:
Rails.cache.fetch("my_cached_objects") do
# generate your objects here if there was a cache miss
[ 'first-object', 'second-object' ]
end
As you can see, you don't even have to call cache.write, you can just use fetch and whenever there is a cache miss the block given will be called and your objects will be created.
You can read more about rails caching here and you can see all supported methods of the ActiveSupport::Cache::Store here.
Another method without using ObjectSpace but still with an ugly solution, now using alias_method:
module Counter
def self.included( base )
base.extend(ClassMethods)
base.class_eval do
alias_method :initialize_without_counter, :initialize
alias_method :initialize, :initialize_with_counter
end
end
def count_class_variable_name
:"###{self.class.name.downcase}_instances"
end
def initialize_with_counter( *args )
unless self.class.class_variable_defined?(count_class_variable_name)
self.class.class_variable_set(count_class_variable_name, [])
end
self.class.class_variable_get(count_class_variable_name) << self
initialize_without_counter(*args)
end
module ClassMethods
def all_instances
class_variable_get(:"###{name.downcase}_instances")
end
end
end
class Person
def initialize
puts 'new person'
end
include Counter
end
p1 = Person.new
p2 = Person.new
p3 = Person.new
puts Person.all_instances.size
lib/keeper.rb
def initialize
instance_eval "###{self.class.to_s.downcase}_instances ||= []"
instance_eval "###{self.class.to_s.downcase}_instances << self"
end
def self.instances
return class_eval "###{self.to_s.downcase}_instances"
end
person.rb
class Person
eval File.open('./lib/keeper.rb','rb').read
end
Then this works:
Person.new
Person.new
Person.instances

Ruby: having callbacks on 'attr' objects

Essentially I'm wondering how to place callbacks on objects in ruby, so that when an object is changed in anyway I can automatically trigger other changes:
(EDIT: I confused myself in my own example! Not a good sign… As #proxy is a URI object it has it's own methods, changing the URI object by using it's own methods doesn't call my own proxy= method and update the #http object)
class MyClass
attr_reader :proxy
def proxy=(string_proxy = "")
begin
#proxy = URI.parse("http://"+((string_proxy.empty?) ? ENV['HTTP_PROXY'] : string_proxy))
#http = Net::HTTP::Proxy.new(#proxy.host,#proxy.port)
rescue
#http = Net::HTTP
end
end
end
m = MyClass.new
m.proxy = "myproxy.com:8080"
p m.proxy
# => <URI: #host="myproxy.com" #port=8080>
m.proxy.host = 'otherproxy.com'
p m.proxy
# => <URI: #host="otherproxy.com" #port=8080>
# But accessing a website with #http.get('http://google.com') will still travel through myproxy.com as the #http object hasn't been changed when m.proxy.host was.
Your line m.proxy = nil will raise a NoMethodError exception, since nil does no respond to empty?. Thus #http is set to Net::HTTP, as in the rescue clause.
This has nothing to do with callbacks/setters. You should modify your code to do what you want (e.g. calling string_proxy.blank? if using activesupport).
I managed to figure this one out for myself!
# Unobtrusive modifications to the Class class.
class Class
# Pass a block to attr_reader and the block will be evaluated in the context of the class instance before
# the instance variable is returned.
def attr_reader(*params,&block)
if block_given?
params.each do |sym|
# Create the reader method
define_method(sym) do
# Force the block to execute before we…
self.instance_eval(&block)
# … return the instance variable
self.instance_variable_get("##{sym}")
end
end
else # Keep the original function of attr_reader
params.each do |sym|
attr sym
end
end
end
end
If you add that code somewhere it'll extend the attr_reader method so that if you now do the following:
attr_reader :special_attr { p "This happens before I give you #special_attr" }
It'll trigger the block before it gives you the #special_attr. It's executed in the instance scope so you can use it, for example, in classes where attributes are downloaded from the internet. If you define a method like get_details which does all retrieval and sets #details_retrieved to true then you can define the attr like this:
attr_reader :name, :address, :blah { get_details if #details_retrieved.nil? }

Resources