rails: methods from module included in controller not available in view - ruby-on-rails

Strange thing – I have Authentication module in lib/ like this:
module Authentication
protected
def current_user
User.find(1)
end
end
and in ApplicationController I'm including this module and all helpers, but method current_user is available in controllers, but not from views :( How can I make this work?

If the method were defined directly in the controller, you'd have to make it available to views by calling helper_method :method_name.
class ApplicationController < ActionController::Base
def current_user
# ...
end
helper_method :current_user
end
With a module, you can do the same, but it's a bit more tricky.
module Authentication
def current_user
# ...
end
def self.included m
return unless m < ActionController::Base
m.helper_method :current_user # , :any_other_helper_methods
end
end
class ApplicationController < ActionController::Base
include Authentication
end
Ah, yes, if your module is meant to be strictly a helper module, you can do as Lichtamberg said. But then again, you could just name it AuthenticationHelper and put it in the app/helpers folder.
Although, by my own experience with authentication code, you will want to have it be available to both the controller and views. Because generally you'll handle authorization in the controller. Helpers are exclusively available to the view. (I believe them to be originally intended as shorthands for complex html constructs.)

Did you declare it with
helper :foo # => requires 'foo_helper' and includes FooHelper
helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
in your ApplicationController?
http://railsapi.com/doc/rails-v2.3.3.1/classes/ActionController/Helpers/ClassMethods.html#M001904

Related

Calling super in ApplicationController rails class

I have this code:
class ApplicationController < ActionController::Base
def authenticate_user!(*_args)
super
end
end
In authenticate_user! I call super, which should call authenticate_user! from ActionController::Base, which is an abstract class.
I couldn't find authenticate_user! inside ActionController::Base, so I suppose there is some meta programming involved(?).
How is that authenticate_user! from Devise ends up in ActionController::Base? Or any other method that is called by using super in ApplicationController?
authenticate_user! is a method that id dynamically built by devise, so you have to monkey patch devise. Helpers are available in both controllers and views, so that's probably why you're not hitting ActionController::Base
If you need to override the functionality you'll need to monkey patch this class: https://github.com/plataformatec/devise/blob/88724e10adaf9ffd1d8dbfbaadda2b9d40de756a/lib/devise/controllers/helpers.rb#L148
You can override the authenticate_user! method by defining your own. First, you'll have to create the directory lib/devise/controllers and add a file called helpers.rb, to which you can add:
module Devise
module Controllers
module Helpers
module ClassMethods
def authenticate_user!
# if something
# do something
# else
super
# end
end
end
If you aren't using devise, post a comment and I'll delete this answer

How to use reusable controller methods in Rails?

I'm relatively new to Rails and am working on creating a simple user authentication system to get to grips with how Rails works.
I'm currently at the point where I'd like to create some methods that I can use in my controllers like so:
is_logged? # => true
and
current_user_id # => 6
These would be used to interact with sessions, mainly so I'm not repeating myself in the controller.
Where would I define these functions and how would I include them in a controller?
Thanks a lot in advance for any help.
Method 1
You can define these method in helper files, inside app/helpers/my_module.rb. You can create a module there, put all the methods inside of it, and then include the modules in your control to use these method.
module MyMoule
def is_logged?
...
end
end
Then in you class include the module
class MyClassController < ApplicationController
include MyModule
def my_method
#Use it like this
logged_in = MyModule.is_logged?
end
end
Method 2
If you using session related stuff you can always put them inside application_controller.rb. And since all your controller will inherit ApplicationController the methods will be available to you.
class ApplicationController < ActionController::Base
def is_logged?
...
end
end
In your other controller you can use them directly.
class MyClassController < ApplicationController
def my_method
logged_in = is_logged?
end
end

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

where to put helper methods for controllers only?

I am looking to write certain methods for processing strings, and other tasks that take place in numerous of my controllers. I know its bad practice to include helpers in your controller, so I was just wondering, where is the best place to put application wide methods used in controllers?
I realize some of you will say to put them in models, but you have to realize that not all my controllers have an associated model. Any and all input would be appreciated.
I tend to put them into helpers. The fact that they are included in views
automatically haven't been a problem for me. You can also place them into
something like app/concerns/ or lib/
I don't like cluttering ApplicationController with private methods
because this often becomes a mess.
Example:
module AuthenticationHelper
def current_user
#current_user # ||= ...
end
def authenticate!
redirect_to new_session_url unless current_user.signed_in?
end
end
module MobileSubdomain
def self.included(controller)
controller.before_filter :set_mobile_format
end
def set_mobile_format
request.format = :mobile if request.subdomain == "m"
end
end
class ApplicationController
include AuthenticationHelper
include MobileSubdomain
end
If you need to use a method in the application scope then I would suggest that you keep those methods inside the application controller and in order to use them inside views.. declare those as helper methods.
For example,
class ApplicationController < ActionController::Base
helper_method :current_user, :some_method
def current_user
#user ||= User.find_by_id(session[:user_id])
end
def some_method
end
end
I would suggest to put them in lib folder. So for example I have:
lib/utils/string_utils
module StringUtils
def foo
...
end
end
class BarController < ActionController::Base
include StringUtils
end
This demonstrates good methodology called Fat model, Thin controller, in this case we are using Mixins instead of Models to separate logic but idea is same. You want your controllers as simple as possible.
It all depends on your needs. I will provide here 2 examples. Both of them are just a custom libraries, located under lib directory.
First example - "custom string processing"
# lib/filters.rb
module Filters
# Converts value to canonical view
def self.phone(value)
# remove all non-digits
clean_value = value.gsub(/\D/, '')
country_codes = configus.phone.country_codes
area_code = configus.phone.defaults.area_code
case clean_value.length
when 7
"#{area_code}#{clean_value}"
when 11
# remove country code only if phone starts with the allowed country code
if country_codes.include?(clean_value[0].to_i)
clean_value[1..-1]
else
clean_value
end
else clean_value
end
end
# usage
# app/api/phones_controller.rb
class Api::PhonesController < Api::ApplicationController
def exists
if params[:q]
clean_value = Filters.phone(params[:q])
...
end
end
end
Second example - helper for flash messages
# lib/flash_helper.rb
module FlashHelper
def flash_translate(key, options = {})
scope = [:flash, :controllers]
scope += params[:controller].split('/')
scope << params[:action]
t(key, {:scope => scope}.merge(options))
end
end
# app/application_controller.rb
class ApplicationController < ActionController::Base
include FlashHelper
end
# usage
# app/your_controller.rb
class YourController < ApplicationController
def create
#object = Object.new(params[:object])
if #object.save
flash[:success] = flash_translate(:success)
...
end
end
end
Note: do not forget to add lib dir to the autoload paths. In config/application.rb add/modify this line config.autoload_paths += %W(#{config.root}/lib).
So for me the answer is lib directory.
Starting from Rails 4 there is a dedicated folder for it app/controllers/concerns. So you can create a module there and then include it in a specific controller(s) or in ApplicationController if you need it available throughout all your controllers.
In case those methods are used in numerous controllers, I would define them in application_controller.rb. Every controller will inherits from it and will be capable to use any method defined there

how to call a helper method from both view and controller in rails?

I created a helper method for some simple calculation. This helper method will just return an integer. I need the helper in both controllers and views.
Unfortunately, it work well in views but not in controllers. I get the undefined local variable or method error. How can I fix it?
Thanks all
In order to use same methods in both controller and views Add you method in application_controller.rb and make it helper methods.
For example
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
#protect_from_forgery # See ActionController::RequestForgeryProtection for details
helper_method :current_user
def current_user
session[:user]
end
end
Now you can use method current_user in both controllers & views
I use a following solution. Because I think helper's methods shoud be stored in an appropriate helper module.
module TestHelper
def my_helper_method
#something
end
end
class SomeController < ApplicationController
def index
template.my_helper_method
end
end

Resources