Use variables in different methods? - ruby-on-rails

At this time I need to use three variables in three different methods with the respective file in the view, but I don't want to define each variable in each method.
How can I define the variable just once and have access to the variables from all the three methods?
Those are the methods:
def pendientes
end
def proceso
end
def finalizadas
end
Those are the three variables:
#pendientes = Support.where("estado = ?", 1)
#procesos = Support.where("estado = ?", 2)
#finalizadas = Support.where("estado = ?", 3)
How do I need to define the variables to do it?

If you're working in the context of a controller, you could do something like this:
class MyController < ApplicationController
before_filter :initialize_variables
def pendientes
end
def proceso
end
def finalizadas
end
private
def initialize_variables
#pendientes = Support.where(estado: 1)
#procesos = Support.where(estado: 2)
#finalizadas = Support.where(estado: 3)
end
end
Update:
If you roll with a before_filter, it may be a good idea to add only: [:pendientes, :proceso, :finalizadas] so that future actions added to the controller don't initialize the three variables.
Another option would be to delete the before_filter call and just invoke the initialize_variables method from each of the three existing actions.

Related

How to use delegates in my controller to refactor code?

In my project I am declaring instance variable with the help of before_action callback, but some of my controllers have same callback code. ex:
my golf_courses_users_controller.rb looks like:
private
def require_user_club_and_golf_course
#club_admin_user = User.find(params[:user_id])
#club = Club.find(params[:club_id])
#golf_course = GolfCourse.find(params[:golf_course_id])
end
my course_holes_controller.rb looks like:
private
def initialize_objects
#user = User.find(params[:user_id])
#club = Club.find(params[:club_id])
#golf_course = GolfCourse.find(params[:golf_course_id])
end
An easy way to set this up is to have the method assigning the instance variables in a parent class (for the sake of simplicity, I'll use ApplicationController here), and then call the before_action in the relevant controllers.
application_controller.rb
def initialize_objects
#user = User.find(params[:user_id])
#club = Club.find(params[:club_id])
#golf_course = GolfCourse.find(params[:golf_course_id])
end
golf_courses_users_controller.rb
before_action :initialize_objects
course_holes_controller.rb
before_action :initialize_objects
Depending on how widespread the use of this before action will be, you could even move the before_action to the same parent controller, and skip this where not needed:
application_controller.rb
before_action :initialize_objects
a_controller_not_using_the_before_action.rb
skip_before_action :initialize_objects
That seems dry, clean and pretty conventional to me - let me know what you think and if you have any questions.
I would produce a helper and use it everywhere:
module DbHelper do
def self.user_club_course(params)
# maybe raise unless
# params.values_at(*%i[user_id club_id golf_course_id]).none?(&:nil?)
[
User.find(params[:user_id]),
Club.find(params[:club_id]),
GolfCourse.find(params[:golf_course_id])
]
end
end
And use it like:
#user, #club, #golf_course = DbHelper.user_club_course(params)

Are arguments passed into UserMailer available to before_actions?

I want to assign the same set of instance variables for multiple emails based on the argument passed into mailer. Something like this:
class UserMailer < ActionMailer::Base
before_action -> { set_defaults(order) }, only: [:email1, :email2]
def email1(order)
...
end
def email2(order)
...
end
private
set_defaults(order)
#order = order
#customer = order.customer
#price = order.price
end
end
I see that you can pass params, strings, and the like to before_actions in controllers: Rails 4 before_action, pass parameters to invoked method
And it looks like I can use process_action as workaround: Rails before_action for ActionMailer that would use mailer arguments
But is there a way to access arguments? Are they out of scope? Help.
This ?
DO_ME_BEFORE = [:email1, :email2]
def process_action(*args)
return super unless DO_ME_BEFORE.include?(args[0].to_sym)
#order = args[1]
#customer = #order.customer
#price = #order.price
super
end
Edit:
I don't think you can hook exactly in the same way as with before_action, but you can simulate it, since your args[0] will be the name of the method. If you write the array of allowed methods as strings, you don't need to call .to_sym on args[0] on the .include?()

Rails can a class variable be assigned within a controller's instance method?

In Rails, can I create a class variable that can be shared between the different instance methods? Just trying to avoid an unnecessary call if possible. Sorry guys, taking this project over last minute from another developer. I haven't coded Rails in 2 years and excited to be getting back into it.
Here's example code:
class Api::VideoEpisodesController < Api::ApiController
# GET /video_episodes
# GET /video_episodes.json
def index
# can I share ##video_episodes with the set_video_episode method?
# or just #video_episodes = VideoEpisode.where(season_number: params[:season_number]) because can't do what I intend?
##video_episodes = VideoEpisode.where(season_number: params[:season_number])
end
# GET /video_episodes/1
# GET /video_episodes/1.json
def show
set_video_episode
end
private
# Use callbacks to share common setup or constraints between actions.
def set_video_episode
# would I be able to access ##video_episodes from the index method or
# is the best way to go instance variable:
# #video_episodes = VideoEpisode.where(season_number: params[:season_number])
# #video_episode = #video_episodes.find(params[:id])
#video_episode = ##video_episodes.find(params[:id])
end
end
Your best bet here is to set up a before_action (or before_filter prior to Rails 5.)
class Api::VideoEpisodesController < Api::ApiController
before_action :set_video_episode, only: [:index, :show]
def index
end
def show
end
private
def set_video_episode
#video_episode = VideoEpisode.find(params[:id])
end
end
Now you have access to #video_episode in both the index and show actions.

How to efficiently instantiate instance variables across multiple controllers

consider the following instance variables
#categories = Category.all
#posts = Post.order("created_at DESC")
i want to use them across multiple controllers as part of the footer, what is the most efficient way to do it?
I see TWO ways to do so:
FIRST:
I would do it using inheritance.
class GenericController < ApplicationController
// Declare your class variables here
end
and then
class MyController01 < GenericController
end
class MyController01 < GenericController
end
.
.
.
Then the class variables would be available in the descendant classes.
SECOND:
Another possibility, easier to implement, is putting these variable directly in app/controller/application_controller.rb. Remember all controllers are descendant of this one.
Then you may just use these variables directly in your layout(s) and everything will be fine.
Personally, I prefer composition to inheritance. So, I might create
# app/controllers/shared_methods/load_footer_variables.rb
module SharedMethods
module LoadFooterVariables
def load_footer_variables
#categories = Category.all
#posts = Post.order("created_at DESC")
end
end
end
Now, in every controller where you want to load your footer variables, do
#app/controllers/foo_controller.rb
class FooController < ApplicationController
include SharedMethods::LoadFooterVariables
before_action :load_footer_variables, :only => [:method_a, :method_b]
def method_a
...
end
def method_b
...
end
def method_c
...
end
end
The include SharedMethods::LoadFooterVariables call makes the methods in the module available within the controller. The before_action call instructs the controller to call the load_footer_variables method prior to method_a and method_b (but not method_c).
If you always want the load_footer_variables called for every action in the controller, then omit the :only argument. You can also use :except if it's more convenient to exclude action rather than include them.

Access to class instance variable

How can I read a class variable? In my case I can't get value from variable.
class MediaContentsController < ApplicationController
#randomUsrId = rand(100)
def create
puts #randomUsrId
end
end
First of all, #randomUsrId refers to an instance variable, not a class variable. You can access it through an instance of the class, not direct on the class. For a class variable, you should use ##randomUsrId.
What you are actually looking for is attr_accessor :randomUsrId, through this, you can read it on an instance method, and even can set it through an instance of the class.
Here's how:
class MediaContentsController < ApplicationController
attr_accessor :randomUsrId
#randomUsrId = rand(100)
def create
puts #randomUsrId
end
end
But #randomUsrId = rand(100) won't set #randomUsrId to a random number, at least it is not the recommend way. You should use before_action here.
class MediaContentsController < ApplicationController
attr_accessor :randomUsrId
before_action :set_user_id_to_a_random_number, only: :create
def create
puts #randomUsrId
end
private
def set_user_id_to_a_random_number
#randomUsrId = rand(100)
end
end
Edit:
Each time you call the set_user_id_to_a_random_number function, it will generate a different number based on rand(100) and store it inside #randomUsrId. If that's what you do not want, and you want to persist the same value, you can do something like following:
def set_user_id_to_a_random_number
#randomUsrId = rand(100) unless defined? #randomUsrId
end
Edit:
What I have stated works only for one request, if you have multiple request, it won't work. As Ryan Bates says here:
An instance variable only sticks around for a single request, so using the technique described will only benefit you if you need to call a method multiple times per request.
That leaves you with two options if you want to store something between multiple requests. Either you can go with Databases, or you can use something called memcached.
You probably doing something wrong in your code, since this isn't how Rails controller logic should be usually implemented, but let's get down to your question anyway. As I mentioned it isn't class variable, it's instance variable in class scope, so in order to access it, you should first get it from that scope:
class MediaContentsController
#randomUsrId = rand(100)
def create
puts self.class.get_random_usr_id
end
def self.get_random_usr_id
#randomUsrId
end
end
MediaContentsController.new.create
# => 44

Resources