What scope can delayed_job access - ruby-on-rails

I'm trying to use delayed_job to handle some tasks, but it keeps telling me it cannot see the functions in my library. I've included the library in the model where I'm calling delay on the method call.
Job.delay.save_job_data(job_id)
def self.save_job_data(job_id)
job = Job.find_by(id:job_id)
file = Marshal.dump(job.image_data)
save_file_to_AWS(file,job.file_name)
...
end
MyLibray
def save_file_to_AWS(file,file_name)
...
end
end
Is there a way for a method call though delay to access other parts of my code?

I've had this issue before and the way I've "fixed" it is by doing the following:
Created an initializer file config/initializers/load_classes_for_dj.rb and put something like this in it:
MyLib::MyClass1
MyLib::MyClass2
# init all classes inside lib/communication for delayed job
Dir["#{Rails.configuration.root}/lib/communication/**/*.rb"].each do |file|
require file
# get the ruby files, remove extension and camelize in order to get the class name
class_name = File.basename(file, ".rb").camelize
# evaluate class name; this will notify environment about class's existence
eval(class_name)
end
If there's a better answer, I'b be happy to see it here!

It occurred to me that my issue might be related to the fact that I was calling the method as a procedure call since there was no real structure involved. I changed the call to a call on class by wrapping my utilities in a utility class and then calling them via Utility.method.
Delayed_job was happy with that. I didn't proceed with Abdo solution since I don't need it yet, but I'll keep it noted incase I run into the issue again, maybe then we'll know what change pushed delayed_job over the edg.

Related

Using require/require_relative method in def initializer is ok?

I did not find the correct place to use the require method in any documentation. I understand that it is desirable to use the require method at the very beginning of the script, but is it possible and how correct is it to use the require method in the initializer class constructor?
Usually i make like this
require 'my_file'
how good is it to do the option below
class MyClass
def initialize
require 'my_file'
end
end
Read require method documentation
I did not find the correct place to use the require method in any documentation.
The "correct" place depends on your requirements and also on your coding style.
is it possible and how correct is it to use the require method in the initializer class constructor?
It is possible. Whether it is "correct" or not depends on your definition of "correct" and it depends on what you want to do.
require only does three things:
Search for a file in the load path.
Check whether the file was already run.
If it wasn't, run the file.
That's all require does.
If you require a file in the initializer, require will only run when you call the initializer (which is usually when you instantiate a new object).
If you need some functionality from the file before you instantiate an object, you are out of luck, since the require will not have run.
Also, you will run require every time you instantiate an object, but since require only runs the file once, that will simply be a waste of time, since it will still search for the file and check whether it was already run every time.
Lexically nesting a call to require like this can also be confusing. Someone who is not familiar with Ruby may assume that by requireing myfile inside the initialize method, the definitions inside my_file might be scoped purely to the initialize method, but that is obviously not the case: require simply runs the file, it does not perform any scoping. The definitions inside my_file will be defined wherever my_file says they are.
In the same vein, someone who is reviewing your code might assume that you think that this creates some sort of scoping and might now wonder whether your code has some sort of bug or (worse) security leak based on that assumption.
And note that "someone who is reviewing your code" might very well be yourself in two years, when you have no idea anymore why you wrote the code this way.
You can put it on top of the file before the class declaration. So you have:
require 'my_file'
class MyClass
def initialize
end
end
It's possible, it will work correctly, but it's highly unusual. I guarantee this will raise questions in code review.
Normally, requires are placed on top of the file.
Declaring the require "./file_name" is not recommended to use in the constructor method as it is often used to create the instance variable and particularly: if you are going to use an instance or global variable from that required file class as a parameter to the initialize (constructor) method of the current class, it may end up with an error.
You may use these ways to require the file at the top of the class:
require 'my_file'
class MyClass
def initialize
puts "this is a constructor"
end
end
or you may also require it just before calling your class is highly recommended to use require
class MyClass
def initialize
puts "this is a constructor"
end
end
require 'my_file'
object = MyClass.new
object.some_method
This allows you to use all the instance, class, method, object...etc.. in your current class.

Override method Ruby

I would like to override the method: authorize_endpoint_url from the Gem in a Rails application: https://github.com/AzureAD/omniauth-azure-activedirectory/blob/master/lib/omniauth/strategies/azure_activedirectory.rb
I tried to do it by adding a file to config/initializers/oauth.rb
With the code:
module OmniAuth
module Strategies
# A strategy for authentication against Azure Active Directory.
class AzureActiveDirectory
def request_phase
debugger
"www.hans.com"
end
end
end
end
But this approach doesn't seem to work, nothing get's actually overwriten. What do I wrong? Thank you
When writing "monkey patch" style alterations you'll want to ensure they're loaded correctly. One way to test this is, after all is said and done, to interrogate Ruby to find out which method is actually being used:
OmniAuth::Strategies::AzureActiveDirectory.instance_method(:‌​request_phase).sourc‌​e_location
The instance_method call returns an object with information about that method and the source_location property tells you where that was defined.
If if's your method, great, you got it loaded right. If not you may need to check that you're hooking in at the correct time.

How do I filter or remove logging of ActiveJob arguments?

I'm using Rails' ActiveJob, and one of my jobs take a raw email as input. When debugging, this can result in a huge amount of noise in my application log. How can I avoid that?
[ActiveJob] Enqueued EmailParserJob (Job ID: 9678f343-c876-4f9f-9cc7-db440634e178) to DelayedJob(default) with arguments: "NOISE"
See https://github.com/rails/rails/blob/4-2-stable/activejob/lib/active_job/logging.rb#L10
ActiveJob::Base.logger = Logger.new(nil)
One thing that may be useful to note here: In any instance of a class that is subclassed from (Rails 5.1) ActiveJob::Base (or, any class instance called by a class subclassed from ActiveJob::Base) The normal Rails.logger.info('log this') commands are going to get logged to the rails console (presumably via STDOUT).
I haven't quite figured out the mechanism that causes this hijacking of Rails.logger, but you can switch to ActiveJob::Base.logger and use the knowledge of this: (https://github.com/rails/rails/blob/b205ea2dc6c70b2b8e2134640e3056ed33fdc6be/activejob/lib/active_job/logging.rb#L13) to change the behavior as you wish.
So, this allows you to log as you want:
1) Include require "active_job/logging" in your application.rb
2) In config/development.rb (or whatever environments you want) include this line:
config.active_job.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new("log/#{Rails.env}.log"))
3) Any logging inside of subclasses of ActiveJob, use this for logging:
ActiveJob::Base.logger.info('(MyJob) Inside of a job but not going to STDOUT')
If anyone can point out the code that explains why Rails.logger.info behaves differently when inside of an ActiveJob class that would be some good reading.
It seems the only way is to override ActiveJob's internal logging method:
class ActiveJob::Logging::LogSubscriber
private def args_info(job)
''
end
end
Put it somewhere into app/initializers/active_job_logger_patch.rb.
I used after_initialize to hook beforehand. It turned out to work only in perform_start method but not enqueue.
Using on_load method to hook works. I think it's the lazyload feature in Rails causing the class to be loaded after the override.
ActiveSupport.on_load :active_job do
class ActiveJob::Logging::LogSubscriber
private def args_info(job)
# override this method to filter arguments shown in app log
end
end
end
From Rails 6.1, you can turn off the logging with log_arguments like the below. This will turn off logging the arguments for all the jobs derived from ApplicationJob, You can also set it on per job basis.
class ApplicationJob < ActiveJob::Base
self.log_arguments = false
end
Reference:
https://github.com/rails/rails/pull/37660
It looks like they added the feature Add an option to disable logging for jobs with sensitive arguments in Rail 6. This would prevent any arguments from appearing in the log lines.
Edit: To use this with ActionMailer, using a custom mailer job might work, haven't tested this myself yet.
Found the following recommendation here:
ActiveJob::Base.logger = Logger.new(IO::NULL)
Seems to be better than passing a nil

Call method on subclass from the parent class when a file is run

I have a number of cleanup scripts in my Rails application which are all classes that inherit from a common CleanupScript class. In order to run a cleanup script, I usually write Script.run unless Rails.env.test? at the bottom of each file (so that it can be run through rails runner).
Obviously, this is not particularly DRY, and I'm thinking that there must be a way within the superclass to set this up automatically. I'm aware of Kernel#at_exit, but I'm not sure if I can somehow use this within CleanupScript to know which script class to use, or if this is even the correct process?
at_exit does seem to be an appropriate way to solve this problem, this is what I ended up doing:
class CleanupScript
cattr_accessor :autorun
self.autorun = !Rails.env.test?
def self.inherited(klass)
at_exit do
klass.run if klass.autorun
end
end
end
This allows subclasses to specify SubclassedCleanupScript.autorun = false if I want to disable autorun for some reason (and also automatically disables autorunning for the test env), but in general will automatically run the class when its script is loaded by rails runner.

How to automatically include Gem in the path?

I have foo.gem and there is lib/foo.rb in there.
When I add gem to Gemfile it's foo.rb is automatically required in my path. But I need to include it automatically. Reason for this is I am making console extension and I want them to be available without me writing `include Foo'.
I am experimenting with
SOME_CLASS.send(:include, Foo)
But not sure what class to use to have it added to the path e.g. when I start console that is automatically included. Here are some mixins automatically included in console, I need mine to be there :) Thank you
irb(main):006:0> self.class.included_modules
=> [PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Dependencies::Loadable, Kernel]
P.S.
I can solve problem with initializer but I don't want to change project's code I just want to add gem and that it works.
You should use the Kernel module, which is included by Object. It's where private methods like exit, puts and require are defined, so it is an excellent choice for defining an imperative API.
When you extend Object, people expect to be able to call your methods explicitly on any object, and they also understand that your method depends on that object's state.
Kernel methods understood differently. Even though they're technically available to all objects, you don't expect people to write things like:
'some string'.sleep 1000
This makes no sense. sleep has nothing to do with the string; it doesn't depend on it in any way. It should only be called with an implicit receiver, as if the very concept of self didn't exist.
Making your methods private and extending Kernel instead helps you get that message across.
You can do that in foo.rb:
module Foo
# …
end
Some::Class.send :include, Foo
When you load or require some file, it is executed line by line. You can put arbitrary code anywhere in the file, even inside module and class definitions. You can take advantage of that in order to properly set up your library so that others don't have to.
Did you tried
Object.send(:include,Foo)
or
self.send(:include,Foo)
inside your console

Resources