Choosing a controller for a layout class instance variable in Rails - ruby-on-rails

I have a DateTime class instance variable #current_year = DateTime.now.year, which I have set into a footer partial. This partial is rendered across several of my clientside pages (and across multiple controllers as <%= render 'layouts/page_footer' %> in the main body of the page - the layout/application.html.erb page is reserved for the site navigation, so the format will not accommodate it there. While I could declare it for every page method it appears on in the controller, I'd find something a little more DRY. Is there a single place I can define my time variable to call in my layout component?

You could add a set_year action in your ApplicationController, something like:
class ApplicationController < ActionController::Base
private
def set_year
#current_year = DateTime.now.year
end
end
And then call it in a before_action in your relevant controller actions. Something like:
class FooController < ApplicationController
before_action :set_year, only: [:some_action, :another_action]
end
Alternatively and riffing off MrYoshiji's comment, you could create a current_year action in ApplicationController, something like:
class ApplicationController < ActionController::Base
def current_year
#current_year ||= DateTime.now.year
end
end
In which case, you could use current_year in your partial instead of #current_year. And then, as MrYoshiji says, you could move that into a helper if that sort of things floats your boat. Something like:
module ApplicationHelper
def current_year
#current_year ||= DateTime.now.year
end
end
The upside, I suppose, of moving current_year into a helper is that it de-clutters your ApplicationController. The downside, I further suppose, is that it obsfucates (to some degree), the source of the current_year action. Again, you'll have to take your boat floating coefficient into consideration.
BTW, #current_year isn't a DateTime. It's a Fixnum.

you could create a method in application_helper.rb file
and use it anywhere you like.
def current_year
#current_year = DateTime.now.year
end

Related

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.

Accessing variables from multiple models

I have six distinct sections of my Rails application, all of which have their own models, views, and controllers.
I'm trying to create a "dashboard" page that accesses variables from each of the sections. For instance, in one of my controllers, I have this condition:
if #retirementsavingsdiff < 0
#retiregrade = "pass"
end
I can't seem to access this variable from a different view/controller though.
Do I put my dashboard logic in application_controller.rb?
A good option for making code reusable is separating it out into modules. Rails 4 includes something called Concerns that make this really easy. Here's a blog post with a good illustration of using Concerns for Controllers, and here's a sample of what your code might look like:
# /app/controllers/concerns/retirement_grade_checker.rb
module RetirementGradeChecker
extend ActiveSupport::Concern
def check_retire_grade
#retirementsavingsdiff = params[:retirementsavingsdiff]
if #retirementsavingsdiff < 0
#retiregrade = "pass"
end
end
end
# /app/controllers/retirement_controller.rb
class RetirementController < ApplicationController
include RetirementGradeChecker
def index
check_retire_grade
#... other stuff
end
end
# /app/controllers/dashboard_controller.rb
class DashboardController < ApplicationController
include RetirementGradeChecker
def index
check_retire_grade
#... other stuff
end
end
I would avoid using view helpers and instead create a new class or module with all of your logic inside. By doing that you can reuse that logic whenever you need it.
Why do this instead of helpers? You can easily test it.
methods defined inside helpers are automatically available across all views.
if you want to convert a method defined inside the controller to a helper method, you can do that too:
def my_method
# code
end
helper_method :my_method
UPDATE:
here is an example from API
class ApplicationController < ActionController::Base
helper_method :current_user, :logged_in?
def current_user
#current_user ||= User.find_by(id: session[:user])
end
def logged_in?
current_user != nil
end
end

How do I initialise objects in a partial view for use by multiple controllers?

I hope this is something obvious that I've just consistently overlooked and the community can set me on the right path.
I have a news article controller, but I want to be able to use a "common" ticker list on different views. How do I initialise this "#article_list" if I'm using the partial in a few controllers? Apparently it is of the opinion that using a helper is not the solution, since helpers are just for view logic. So where do I put this initialiser that would be available to every controller as required? I shouldn't put them in application controller should I?
You can use before_filter method, i.e. something like this:
class ApplicationController < ActionController::Base
def set_article_list
#article_list = ArticleList.all # or any onther selection
end
end
class NewsArticleController < ApplicationController
before_filter :set_article_list, only: :action1
def action1
end
end
class AnotherNewsArticleController < ApplicationController
before_filter :set_article_list, only: :another_action1
def another_action1
end
end
UPDATE:
Indeed, there will be problem with a fat ApplicationController. To avoid it it's possible to use module (almost #carolclarinet describe it below):
module ArticleList
def set_article_list
#article_list = ArticleList.all # or any onther selection
end
end
class NewsArticleController < ApplicationController
include ArticleList
before_filter :set_article_list, only: :action1
def action1
end
end
class AnotherNewsArticleController < ApplicationController
include ArticleList
before_filter :set_article_list, only: :another_action1
def another_action1
end
end
And
You can create, essentially, a query object that is only responsible for returning what you need for #article_list, for example, building off of Psylone's answer:
class ArticleList
def ticker_articles
ArticleList.all # or any onther selection
end
end
This class could go in lib, app/models, app/query_objects, app/models/query_objects, wherever it makes sense for you. This is a bit outside The Rails Way so there's no convention about where these types of objects should live.
Then in whatever controller you need this, do:
#article_list = ArticleList.new.ticker_articles
For more explanation of query objects, see this codeclimate article #4. Depending on what you're doing to set #article_list, this might also be called a service object (#2) or something else entirely. No matter what you call it though, its responsibility would be to return the value you need for #article_list and that's it.

Ruby on rails: How can I get values from a database in application.html.erb?

How can I get values from database in application.html.erb? I need to get those values for whole project. Those values will stay forever to all pages. How can I pass values to application.html.erb?
Is there anything like beforeRender?
Is there anything like appcontroller.rb to override actions?
You could use an application wide before_filter - like so
class ApplicationController < ActionController::Base
before_filter :load_application_wide_varibales
private
def load_application_wide_varibales
#var = Model.where :condition => "whatever"
end
end
#var would then be available in all your views
cheers
you can put method in the application controller
before_filter :load_data
def load_data
#data = Data.all
end
All controllers inherits ApplicationController, so data will be loaded at all actions. Now you can use #data at you application.html.erb file
The best way is probably to create a method in your application controller and declare it a helper method. Then you can call that method in application.html.erb. For example if you want to be able to use the current user throughout your application you'd do something like this:
class ApplicationController
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id])
end
end
Then in application.html.erb you can do the following:
Hello <%= current_user.name %>
It's also possible to use before_filter like to other answers suggest, but in this solution the database only gets hit when it's necessary. With before_filter it always gets hit.

how do you put before filters in modular controllers?

I have several controllers that are in a module:
class SoapTest::DashboardController < ApplicationController
class SoapTest::TestCasesController < ApplicationController
etc.
I want to be able to check if a user has certain permissions for a module, and since I don't have a "parent" controller where the above ones inherit, i thought to put the check in a before filter in applications. But I can't seem to get the module name:
in application controller, i have:
before_filter :check_company_features
def check_company_features
puts controller_name
end
but controller_name just returns "dashboard". I need to get the "SoapTest" clause
Be attention, what you currently call modules actually are namespaces.
The reason why controller_name returns only the class name (and not the fully qualified name) is because Rails explicitly strips the namespaces. You can get them by calling the Ruby #name method on the controller class.
class SoapTest::DashboardController < ApplicationController
before_filter :check_company_features
def check_company_features
puts controller_name
# => "dashboard_controller"
puts self.class.name
# => "SoapTest::DashboardController"
end
end
There are several String inflection methods you can call on the #name to get the formatted version.
However, I strongly encourage you to use a namespaced main controller.
Instead of using
class SoapTest::DashboardController < ApplicationController
you can extend a SoapTest::ApplicationController
class SoapTest::ApplicationController < ApplicationController
before_filter :check_company_features
def check_company_features
# ...
end
end
class SoapTest::DashboardController < SoapTest::ApplicationController
end

Resources