ActiveJob uninitialized constant - ruby-on-rails

I have a weird problem with ActiveJob.
From a controller I'm executing the following sentence:
ExportJob.set(wait: 5.seconds).perform([A series of parameters, basically strings and integers])
ExportJob.rb
require_relative 'blablabla/resource_manager'
class ExportJob < ActiveJob::Base
def perform
ResourceManager.export_process([A series of parameters, basically strings and integers])
end
end
When the controller/action is executed for the first time the process goes fine, but the second time an error is thrown:
uninitialized constant ExportJob::ResourceManager
The weird thing is that this is not the only job I have in my project, the other ones are being executed without any problem.
I'm Attaching some information of my project:
development/production.rb
config.active_job.queue_adapter = :delayed_job
Gemfile:
gem 'delayed_job'
gem 'delayed_job_active_record'
Any clue would be a help for me.
Thanks in advance!

Constants don't have global scope in Ruby. Constants can be visible from any scope, but you must specify where the constant is to be found.
Without :: Ruby looks for the ResourceManager constant in lexical scope of the currently executing code (which is ExportJob class, so it looks for ExportJob::ResourceManager).
The following should work (assuming that ResourceManager is defined as a top level constant (eg not nested under any module/class):
class ExportJob < ActiveJob::Base
def perform
::ResourceManager.export_process(*args)
end
end

Related

Rails `NameError: uninitialized constant` only in production (not console) - class is in /app subfolder - needs to add double colon `::`

In a Rails 5.2 app, I have a class Foos::SomethingSerializer, stored in app/serializers/foos/something_serializer.rb.
In Development, this controller code works just fine:
# api/v1/foos_controller.rb
render json: Foos::SomethingSerializer.new(foo).as_json
In Production only, this code raises an exception NameError: uninitialized constant Api::V1::Foos::SomethingSerializer
I've had this before so I just added :: in front of it, like:
# api/v1/foos_controller.rb
render json: ::Foos::SomethingSerializer.new(foo).as_json
I could call it a day, but I would really like to understand this, since these bugs that only bites in Production are the worst.
Also, Rails.configuration.eager_load_paths in the console shows that /app/serializers is on the autoload path, as it should be, as it's a subfolder of app/.
Also, in the production environment console, I can type Foos::SomethingSerializer.new without any exception whatsoever (so it finds the constant).
So why (1) in development this works and (2) in production it throws an exception trying to find that constant namespaced inside the controller and can't find it on the upper Foos namespace?
Ruby has relative constant lookup.
module A
class B
def self.c
C # note that it's not A::C
end
end
end
module A
class C
end
end
class C
end
C # C < Object
A::B.c # A::C < Object
If it can find a constant relatively to where you're looking from, it will return that. If it cannot find the constant in the current context, it will go up a level and look for it there until it reaches root level. If the constant is not found on root level, then an error is raised.
Prepending :: to the constant tells ruby to just start looking from the root level.
In your code, you have both ::Foos and Api::V1::Foos defined. When calling Foos::SomethingSerializer from inside Api::V1, ruby will find Api::V1::Foos instead of ::Foos, but there is no SomethingSerializer there, so it will fail. I know it's inconvenient and I don't personally like it either, but that's how it is. If you know you're looking for something from the root level, adding :: to the start is always safe.
It didn't fail on development, because you have autoloading on. When you called Foos::SomethingSerializer, Api::V1::Foos was not loaded yet and since ::Foos was already loaded, rails found it and didn't try to autoload Api::V1::Foos.
I suggest you run your specs with eager_load = true to attempt to catch errors like this and use root-level lookup (::) whenever you have constants with the same name in both root and nested contexts.

How to successfully inherit ActiveRecord::Base?

How to successfully inherit ActiveRecord::Base?
Environment: Ruby 2.0.0, Rails 4.0.3, Windows 8.1, PostreSQL 9.3.3, Devise 3.2.4
I have an operational app and would like to add a comprehensive logging class to it. This will be a complex class that not only logs messages but also creates an SQL database that logs transactions by object. I need this class available throughout all of the classes in the application.
To do this, I wanted to inherit ActiveRecord::Base into the class and then have all other classes inherit it, though I don't plan to use STI. That seemed to be a lot simpler in concept than in practice, even though I thought such inheritance was a common best practice. Am I missing something?
One of the initial tables was this:
class Device < ActiveRecord::Base
...
end
I set it up like this:
class XLog < ActiveRecord::Base
self.abstract_class = true
def initialize
end
end
class Device < XLog
...
end
Prior to this change, the app was working fine. After this change, when I login I receive:
ArgumentError at /devices/sign_in
wrong number of arguments (1 for 0)
The error occurs in:
bin/rails, line 4
bin/rails is:
#!/usr/bin/env ruby.exe
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'
Device is the Devise "User" class in this application and the error occurs when I try to login. If I change Device to inherit ActiveRecord::Base, it lets me login and run.
But, then I get another error whenever I call "new" on the other classes:
undefined method `[]' for nil:NilClass
I am definitely missing something when it comes to this inheritance. Advice appreciated.
The initialize method was throwing the error. It was triggering every time a subclass was initialized and was configured to accept 0 parameters. When I removed it, the whole thing started working. If I need it, I'll have to configure it to accept a variable number of parameters and pass them as expected, I guess.

rails resque and resque-send-later plugins causing "unitialized constant ClassName::Resque" error

i'm using the resque and resque-send-later PLUGINS (not gems) in my project.
I haven't put 'require' statements anywhere in the code at all (since they're plugins and so they must be included upon initialization).
the app is working perfectly locally, but on heroku, it shows an error
"const_missing: unitialized constant User::Resque"
my User model:
class User < ActiveRecord::Base
include Resque::Plugins::SendLater
def self.testingWorker1
# code to be run in the background
end
end
my User_controller: (where i'm calling the above method from)
class UserController < ApplicationController
def testingResqueWorker
User.send_later(:testingWorker1)
end
end
so I removed the line include Resque::Plugins::SendLater from the my model
it still works perfectly locally, but now on heroku it gives an error saying "method_missing: send_later"
my question is:
1. how do we 'include' or 'require' plugins in rails? are they automatically available to all controllers and models?
2. any ideas for how to fix the above errors?
Two thoughts
any reason why you aren't using the gems?
are you sure the plugins have been added to the git repository and therefore have been deployed to heroku?

delayed_job: NoMethodError

Here is my tiny Rails3 controller:
class HomeController < ApplicationController
def index
HomeController.delay.do_stuff
end
def self.do_stuff
puts "Hello"
end
end
Upon accessing index, the job gets correctly inserted in database:
--- !ruby/struct:Delayed::PerformableMethod
object: !ruby/object:Class HomeController
method_name: :do_stuff
PROBLEM: When executing bundle exec rake jobs:work, I get:
Class#do_stuff failed with NoMethodError:
undefined method `do_stuff' for #<Class:0x0000000465f910>
Despite the fact that HomeController.do_stuff works perfectly. Any idea?
See https://github.com/collectiveidea/delayed_job/wiki/Common-problems#wiki-undefined_method_xxx_for_class in documentation.
It seems that you should have
..object: !ruby/class HomeController method_name ...
in the database, but you have
..object: !ruby/object:Class HomeController method_name ...
instead. Which is bad.
Even delayed_job author don't know the reason. It somehow depends on the webserver you run in on. Try the wiki's recommendation.
I had the same problem.
I found several discussions stating that different yaml parsers were used by when the job was put in the queue by the web application and when it was executed later.
Some suggest the psych parser should be used. Some suggests syck. First I tried psych but ended up with incompability issues with other gems. So I picked syck.
I wasn't able to sort out which configuration files that are used by the web server and the queue. After a lot of experimentation I ended up with the following configurations (all of them in the top of the file):
#application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
require 'yaml'
YAML::ENGINE.yamler= 'syck'
# ...
and
#environment.rb
require 'yaml'
YAML::ENGINE.yamler= 'syck'
# ...
and
#boot.rb
require 'yaml'
YAML::ENGINE.yamler= 'syck'
require 'rubygems'
# ...
I'm using Ruby 1.9.3, Rails 3.2.8, Webrick, delayed_job 3.0.3
I my case the problem was mainly because I was passing Hash as a parameter to object that was passed to delayed_job queue.
But after 25 trails I have come to conclusion that delayed_job accepts objects only with integer as parameter. Hence I stored all the parameters in the database and then passed that record id as parameter to delayed_job and inside the perform function we can access all the parameters with that record id and delete that record after fetching that data.
Delayed::Job.enqueue LeadsJob.new(params[:customer]) # this job will be queued but will never run, this is because of the way Delayed_job serializes and De-serializes the objects.
instead do something like this
#customer = Customer.create(params[:customer])
Delayed::Job.enqueue LeadsJob.new(#customer.id)
If the customer details was just to pass the parameters then delete that record inside the function.
Please ping me if you need more details on the same.
The problem might be also because of the YAML parser that Delayed_Job uses but I haven't tried out that option that is mentioned by #Stefan Pettersson

ruby ::Module or just Module

I'm slowly making my way through the rails source, to get a better grip on ruby and rails in general. In the following rails class test_case.rb
the line is
class TestCase < ::Test::Unit::TestCase
and I was wondering if there is any difference with doing the following
class TestCase < Test::Unit::TestCase
It may seem trivial, but these things matter picking up a new language. The tests still run for ActiveSupport if I remove the leading :: so what does it do... :P
::Test ensures that you get a toplevel module named Test.
The latter case (Test::Unit::TestCase) doesn't ensure that Test is a toplevel module, it could be a class, for example. It means that most of the time, it'll work, but you could accidentally break it.
Imagine you have this code
module UserTesting
class Test # Details about a simple test
end
class TestCases < Test::Unit::TestCase
end
end
# => NameError: uninitialized constant UserTesting::Test::Unit
This would error out since your Test constant available to the class you are creating has no Unit constant in it. If you address it by :: this is like the leading slash in a path.
There is also a special case for using these - you can be evaluating your code in something else than the default root namespace, and there you actually need the double colon to address classes like ::Object (usually to monkeypatch them).

Resources