execute controller method with delayed_job gem - ruby-on-rails

I have a method inside my controller that I need execute inside delayed job method:
This is my order controller action:
class OrdersController < ApplicationController
def create
#code here
order = Order.first
Order.delay(queue: "order", priority: 1, run_at: 2.minutes.from_now).expire_order(order)
end
def template_expired_order(order)
#code here
end
end
This is my order model:
class Order
include Mongoid::Document
include Mongoid::Timestamps::Created
.
.
.
#delayed jobs method
def self.expire_order(order)
#code here
end
end
I want execute the controller method template_expired_order(order) when self.expire_order(order) method is executed or triggered or fired up.
How can I do it?
Thank you very much!

You should not put model-related code in the controller, especially if you want to run it in a background job. It's not clear what template_expired_order does, but I would recommend putting it in the Order model and calling it directly on the order that gets pass into expired_order.
class Order
def expire_order(order)
order.template_expired_order
end
def template_expired_order
# code
end
end

Related

after_commit is never being called

I am on rails 4.2.10. I need to trigger a job using sidekiq in after_save method. But the job is triggered, before the object is committed into the database, so I get the error, object not found with id=xyz.
So, I need to use
after_commit :method_name, :on => [:create, :update]
But the changes that I made in object doesn't show up in above method. I have an attribute email. When I was calling above method after_save, email_changed? return true. But if I call the same method using after_commit, email_changed? returns `false.
Is it because I am using object.save method and not create method?
Below is the method, which I am calling to trigger the job:
def update_or_create_user
if email_changed?
ServiceUpdateDataJob.perform_later action: 'update', data: {type: 'user', user_id: self.id}
end
true
end
I recognize this isn't exactly an answer to your question as stated. However...
IMO, you're overloading your model's responsibilities. I suggest you create a service that triggers the job when your model is saved. It might look something like:
class FooService
attr_accessor :unsaved_record
class << self
def call(unsaved_record)
new(unsaved_record).call
end
end
def initialize(unsaved_record)
#unsaved_record = unsaved_record
end
def call
kick_off_job if unsaved_record.save
!unsaved_record.new_record?
end
private
def kick_off_job
# job logic
end
end
You might use the service in a controller something like:
class FooController < ApplicationController
def create
#new_record = ModelName.new(record_params)
if FooService.call(#new_record)
# do successful save stuff
else
# do unsuccessful save stuff
end
end
...
end

How to add two delayed jobs

I am using delayed_jobs gem. Suppose, I have a ArticleController with following code
#articles.each do |ar|
#call send mail method and add to delay
#call createpdf method and add to delay
end
and another class BackgroundJobs.rb
class BackgroundJobs < ActiveRecord::Base
def sendmail(article_id)
#code to send mail
end
def createpdf((article_id))
#code to generate pdf
end
end
How can I add the send mail and createpdf methods to delayed job in articlecontroller code.
First, i would create class methods instead of instance methods in BackgroundJobs:
class BackgroundJobs < ActiveRecord::Base
def self.sendmail(article_id)
#code to send mail
end
def self.createpdf(article_id)
#code to generate pdf
end
end
And then just call them directly in the controller:
#articles.each do |ar|
BackgroundJobs.delay.sendmail(ar.id)
BackgroundJobs.delay.createpdf(ar.id)
end

Rails, place to put user input parsing

In my Rails app there is a view with a simple user form consisting of a text box and a submit button.
When the user submits the form, depending on his input, different models are created:
class MessageController < ApplicationController
def create
if is_foo params[:text]
Foo.create
else
Bar.create
end
end
def is_foo(text)
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
My question is, do you think that it's a better design to put the "is_foo" logic inside the Foo model instead of the controller like so?
Model:
class Foo < ActiveRecord::Base
def self.is_foo(text)
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
Controller:
class MessageController < ApplicationController
def create
if Foo.is_foo params[:text]
Foo.create
else
Bar.create
end
end
end
On one hand, the model should take care of the logic. On the other, this isn't really logic, its more of an input rule... What do you think guys?
Helper
I'd leave the is_foo out of the model, as model logic should be to do with the model directly, not determining which model should be created / saved
I would personally look at using a helper method for the test - calling the file ControllerHelper or similar:
#app/helpers/controller_helper.rb
class ControllerHelper
def is_foo? text
# Here the message gets parsed
# i.e if text[0] == "M"
end
end
This will allow you to call the helper in your controller, giving you the ability to use the logic to form the fixes:
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
include ControllerHelper
def create
model = is_foo?(params[:text]) ? "foo" : "bar"
model.constantize.send(:create)
end
end
I wouldn't call it a ControllerHelper module as mentioned in Rich Pecks answer (since helpers in Rails are view-related), but something like
# app/lib/foo_bar_creator.rb
FooBarCreator = Struct.new(:params) do
def create
build.save
end
def build
klass.new
end
def is_foo?
params[:text] == 'foo'
end
def klass
is_foo? ? Foo : Bar
end
end
(some call these kind of classes "Service Objects")
This way I could just call FooBarCreator.new(params).create in my controller.

calling methods dynamically inside a controller

I have the following scenario
I want to add methods dynamically to a controller. All my method names are in a table . Please refer the following example
-table (method_names)-
1 - Walk
2 - Speek
3 - Run
and I have a controller
class UsersController < ApplicationController
def index
end
end
Inside this index action i want to call my methods dynamically. Those methods were actually implemented else ware.
I have another controller like
class ActionImplementController < ApplicationController
def walk
puts "I'm walking"
end
def speek
puts "I'm sppeking"
end
def run
puts "I'm running"
end
end
** I have done something like below and its working
class UsersController < ApplicationController
def index
a = eval("ActionImplementController.new.run")
end
end
But my question is , is this the right way or is there anyother way to do this
Thanks in advance
cheers
sameera
While the first answer works, i would prefer something like this
module ImplementsActions
def run
...
end
def walk
..
end
def ...
end
and then in your controller write
class UsersController < ActionController::Base
include ImplementsActions
# now you can just use run/speek/walk
def index
run
end
end
Much cleaner because the code can be shared, but it is defined where you need it.
I think it's generally best to avoid the use of eval. If you can, I would make all your methods class methods and then run them like so:
def index
ActionImplementController.send :run
# ActionImplementController.new.send(:run) works if you can't use class methods
end

Rails ActionController Execute Same Code for Every Action

To the rails experts out there I was wondering where/how you would execute the same code for every action in your web application? If you can point me to an article or provide a short code snippet I would greatly appreciate it.
Thanks in advance to anyone who can help.
Use a filter in your ApplicationController to run the code for every action in your application. All your controllers descend from ApplicationController, so putting the filter there will ensure the filter gets run.
class ApplicationController
before_filter :verify_security_token
def verify_security_token; puts "Run"; end;
end
It sounds to me like you're talking about filters.
class MyController < ActionController::Base
before_filter :execute_this_for_every_action
def index
#foo = #bar
end
def new
#foo = #bar.to_s
end
def execute_this_for_every_action
#bar = :baz
end
end
You can put the filter on the ApplicationController, too, if you want every controller to run it.
before_filter if you want the code to be executed "before" each action.
If you want the action to be declared each time you use it, you can put it in ApplicationController and call the method in any controller.
Another approach is to use helpers like:
module PersonHelper
def eat
{.. some code ..}
end
end
And in your controller:
class MyController < ActionController::Base
include PersonHelper
def index
eat
end
end

Resources