I am new to Ruby on Rails and Sidekiq. I want to set this post request to be done in Sidekiq queue and I don't know how to send it to the perform method
My controller Class code
def create
BaseWorkerJob.perform_async
end
private
def book_params
params.require(:book).permit(:title,:comment)
end
def author_params
params.require(:author).permit(:first_name,:last_name,:age)
end
I tried to make the params methods public but no change
My BaseWorkerJob class code
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry:0
require './app/controllers/api/v1/books_controller.rb'
include Api::V1
def perform
author=
Author.find_or_create_by(
first_name:author_params[:first_name],
last_name:author_params[:last_name],age:author_params[:age])
book = Book.new(BooksController.book_params.merge(author_id: author.id))
book.save
end
end
SideKiq Error
ruby 3.1.2
Rails 7.0.4
author_params is a private method and you are trying to access it outside of the controller.
you can pass author_params to perform the method.
your controller code should be:
def create
BaseWorkerJob.perform_async(author_params)
end
private
def book_params
params.require(:book).permit(:title,:comment)
end
def author_params
params.require(:author).permit(:first_name,:last_name,:age)
end
And BaseWorkerJob class will have below:
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry:0
require './app/controllers/api/v1/books_controller.rb'
include Api::V1
def perform(author_params)
author=Author.find_or_create_by(
first_name:author_params[:first_name],
last_name:author_params[:last_name],
age:author_params[:age])
book = Book.new(BooksController.book_params.merge(author_id: author.id))
book.save
end
I hope this will help you.
Related
I am new to Ruby on Rails and Sidekiq. I want to set this delete request to be done in Sidekiq queue and I don't know how to send it to the perform method, I am sending the Book model to the perform method
My controller Action code
def destroy
BaseWorkerJob.perform_async(Book)
end
My BaseWorkerJob class code
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry:0
def perform(book)
# Do something
book.find(params[:id]).destroy!
sleep 15
end
end
SideKiq Error
enter image description here
ruby 3.1.2
Rails 7.0.4
You can send the model name and object id to the worker
def destroy
BaseWorkerJob.perform_async(Book.to_s, params[:id])
end
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry: 0
def perform(klass_name, object_id)
klass_name.constantize.find(object_id).destroy!
end
end
Try it out!
I have the following class
class EvaluateService
def initialize
end
def get_url
end
def self.evaluate_service
#instance ||= new
end
end
class CheckController < ApplicationController
def index
get_url = EvaluateService.get_url
end
end
The problem here is that i know that i can do evaluate_service = EvaluateService.new and use the object evaluate_service.get_url and it will work fine but i also know that some frown upon the idea of initializing the service object this way and rather there is a way of initializing it via a call, send method in the service class.
Just wondering how do i do this?
I think what you're looking for is something like:
class Evaluate
def initialize(foo)
#foo = foo
end
def self.call(foo)
new(foo).call
end
def call
url
end
private
def url
# Implement me
end
end
Now you can do this in your controller:
class CheckController < ApplicationController
def index
#url = Evaluate.call(params)
end
end
The reason some prefer #call as the entry point is that it's polymorphic with lambdas. That is, anywhere you could use a lambda, you can substitute it for an instance of Evaluate, and vice versa.
There are various ways to approach this.
If the methods in EvaluateService don't need state, you could just use class methods, e.g.:
class EvaluateService
def self.get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = EvaluateService.get_url
end
end
In this scenario, EvaluateService should probably be a module.
If you want a single global EvaluateService instance, there's Singleton:
class EvaluateService
include Singleton
def get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = EvaluateService.instance.get_url
end
end
But global objects can be tricky.
Or you could use a helper method in your controller that creates a service instance (as needed) and memoizes it:
class EvaluateService
def get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = evaluate_service.get_url
end
private
def evaluate_service
#evaluate_service ||= EvaluateService.new
end
end
Maybe even move it up to your ApplicationController.
Is it okay to call a private method of a parent class's subclass from a module which is included in the parent class especially when it concerns ApplicationController, Controllers and lib modules in Rails?
Consider if required to change the controller name the method name to reflect the model name(to Article) change.
I feel this is really bad coding and wanted to know what community thinks about this
Example from a Rails Application:
/lib/some_module.rb
module SomeModule
include SomeModuleResource
def filtering_method
calling_method
end
def calling_method
fetch_object
end
end
/lib/some_module_resource.rb
module SomeModuleResource
def fetch_object
note
end
end
/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include SomeModule
before_action :filtering_method
end
/app/controllers/notes_controller.rb
class NotesController < ApplicationController
def show
end
private
def note
#note ||= Note.find(param[:id]))
end
end
I'm of the opinion that this is not necessary bad, although when you expect a certain interface (methods, variables, etc.) from the class that includes the module I would add the following:
module SomeModuleResource
def fetch_object
note
end
private
def note
raise NotImplementedError
end
end
This way, when #note is called without implementing it (because you forgot it was needed or whatever) a NotImplementedError is raised.
Another option is to work around it and create a more general solution. For example, if all controllers behave the same way you described above you can do the following:
module SomeModuleResource
def fetch_object
note
end
private
def note
klass = params[:controller].classify.constantize
instance = klass.find(params[:id])
var_name = "##{klass.underscore}"
instance_variable_set(var_name, instance) unless instance_variable_get(var_name)
end
end
You could also create a class helper method like before_action so that you can pass your own implementation.
module SomeModule
include SomeModuleResource
def self.included(base)
base.extend(ClassMethods)
end
def filtering_method
calling_method
end
def calling_method
fetch_object
end
module ClassMethods
def custom_before_action(&block)
define_method(:note, &block)
private :note
before_action :filtering_method
end
end
end
Now you can use custom_before_filter { #note ||= Note.find(params[:id]) } in every controller (after including).
The above is just to present you with ideas. I'm sure you could find better solution to the problem, but this hopefully points you in the right direction.
See: Alternatives to abstract classes in Ruby?. Or search for abstract classes in Ruby and you'll find more on this subject.
I have some helpers and private methods in a controller, and I want to have the same helpers and private methods in another controller. So I moved that code to module and tried to include the module in the second controller. But I can't seem to do it, because it says undefined method helper method for the DashboardHelper. Is there anyway to accomplish what I am trying to do?
Here is the code
module DashboardHelper
def get_date(log)
end
def get_working_hours(log)
end
helper_method :get_date, :get_working_hours
private
def employee_params
end
def identify_employee
end
def check_is_arrived
end
def calculate_time_percentage
end
end
class AccountController < ApplicationController
include DashboardHelper
end
hello gates you have to include extend ActiveSupport::Concern in your concern .
This should not be in your helper folder instead pull it somewhere in you concern folder
the end file may look like
module DashboardHelper
extend ActiveSupport::Concern
module ClassMethods
def get_date(log)
end
def get_working_hours(log)
end
helper_method :get_date, :get_working_hours
private
def employee_params
end
def identify_employee
end
def check_is_arrived
end
def calculate_time_percentage
end
end
end
I need to override the behavior of the find method of a class from a gem.
This is the code in the gem:
module Youtube
class Display
attr_accessor :base
def find(id, options = {})
detailed = convert_to_number(options.delete(:detailed))
options[:detailed] = detailed unless detailed.nil?
base.send :get, "/get_youtube", options.merge(:youtube_id => id)
end
end
end
How do I override the above find method in my own YoutubeSearch Controller of my Rails Application?
def find(id, options = {})
//Code here
end
Create a .rb file in config/initializers directory with the following code:
Youtube::Display.class_eval do
def find(id, options = {})
# Code here
end
end
I have elaborated such a solution which DOES NOT require the Rails server restart after every code change (unlike all the other's solutions):
1.
Create YoutubeHelper.rb
module YoutubeHelper
include Youtube
def init_youtube_helper
display.class_eval do
def find(id, options = {})
//Code here
end
end
end
end
2.
youtube_search_controller.rb
class YoutubeSearchController < ActionController::Base
include YoutubeHelper
before_action :init_youtube_helper
end