auth helper methods using application_controller or helper file - ruby-on-rails

I want to create my authentication system from scratch and I'm not really looking for debate in this area. My question is should I be using a helper file to provide methods such as current_user and signed_in? or is it preferred to provide these through the application_controller? or does it not matter in the slightest and I just need to get on with it?

I would put it in the ApplicationController, you can define something like
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
This will allow you to call #current_user from your views and controllers.

Related

Ruby on Rails: Common method available for controllers and views?

I have been working with Ruby on Rails for a short time. Recently I implemented an authentication system for my application. I made a method available on 'application_helper.rb' to retrieve the current logged user (method called current_user).
The method just retrieves my User object if the session[:user_id] variable is present.
However I face the following problem.
If I place the current_user method in 'application_helper.rb', my controllers can't make use of it
If I place the current_user method in 'application_controller.rb', my views can't make use of it
What's the best approach to solve this problem? The easy way would be duplicate my code in both controller and helper, but I know there is a better and more correct way.
Thanks in advance
This is a common and well-solved problem.
Rails doesn't allow controllers to access helper methods. If you want to share a method between your views and controllers, you need to define the method in your controller, and then make it available to your views with helper_method:
class ApplicationController < ActionController::Bbase
# Let views access current_user
helper_method :current_user
def current_user
# ...
end
end
You can pass more than one method name to helper_method to make additional methods in your controller available to your views:
helper_method :current_user, :logged_in?
def current_user
# ...
end
def logged_in?
!current_user.nil?
end

Rails: where does the infamous "current_user" come from?

I've been looking around recently into Rails and notice that there are a lot of references to current_user. Does this only come from Devise? and do I have to manually define it myself even if I use Devise? Are there prerequisites to using current_user (like the existence of sessions, users, etc)?
It is defined by several gems, e.g. Devise
You'll need to store the user_id somewhere, usually in the session after logging in. It also assumes your app has and needs users, authentication, etc.
Typically, it's something like:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
end
This assumes that the User class exists, e.g. #{Rails.root}/app/models/user.rb.
Updated: avoid additional database queries when there is no current user.
Yes, current_user uses session. You can do something similar in your application controller if you want to roll your own authentication:
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end

When should I user before_filter vs helper_method?

I have the following application_controller method:
def current_account
#current_account ||= Account.find_by_subdomain(request.subdomain)
end
Should I be calling it using a before_filter or a helper_method? What's the difference between the two and what should I consider in terms of the trade-offs in this case?
Thanks.
UPDATE FOR BETTER CLARITY
I'm finding that I can user the before_filter instead of the helper_method in that I'm able to call controller defined methods from my views. Perhaps it's something in how I arranged my code, so here is what I have:
controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
before_filter :current_account
helper_method :current_user
end
helpers/sessions_helper.rb
module SessionsHelper
private
def current_account
#current_account ||= Account.find_by_subdomain(request.subdomain)
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
if current_user
return true
else
return false
end
end
end
controllers/spaces_controller.rb
class SpacesController < ApplicationController
def home
unless logged_in?
redirect_to login_path
end
end
end
views/spaces/home.html.erb
<%= current_account.inspect %>
In theory, this shouldn't work, right?
There is no relationship between using before_filter or helper_method. You should use helper method when you have a method in your controller that you would like to reuse in your views, this current_account might be a nice example for helper_method if you need to use it in your views.
They are two very different things. A before_filter is something that you want to be called once before an action starts. A helper method on the other hand gets repeated often, typically in a view.
That method you have there is just fine to stay where it is.
I solved my problem. I'm new to Rails, and didn't know that methods defined in the helpers directory are automatically helper_methods. Now I'm wondering how this effects memory/performance. But at least I have the mystery solved. Thanks everyone for your help!

Ruby on rails global variable?

I'm trying to set the current user into a variable to display "Logged in as Joe" on every page. Not really sure where to begin...
Any quick tips? Specifically, what file should something like this go in...
My current user can be defined as (I think): User.find_by_id(session[:user_id])
TY :)
You might want to use something like Authlogic or Devise to handle this rather than rolling your own auth system, especially when you aren't very familiar with the design patterns common in Rails applications.
That said, if you want to do what you're asking in the question, you should probably define a method in your ApplicationController like so:
def current_user
#current_user ||= User.limit(1).where('id = ?', session[:user_id])
end
You inherit from your ApplicationController on all of your regular controllers, so they all have access to the current_user method. Also, you might want access to the method as a helper in your views. Rails takes care of you with that too (also in your ApplicationController):
helper_method :current_user
def current_user ...
Note: If you use the find_by_x methods they will raise an ActiveRecord::RecordNotFound error if nothing is returned. You probably don't want that, but you might want something to prevent non-users from accessing user only resources, and again, Rails has you covered:
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
before_filter :require_user
private
def current_user
#current_user ||= User.limit(1).where('id = ?', session[:user_id])
end
def require_user
unless current_user
flash[:notice] = "You must be logged in to access this page"
redirect_to new_session_url
return false
end
end
end
Cheers!
It belongs in your controllers.
All your controllers inheirit from Application Controller for exactly this reason. Create a method in your Application Controller that returns whatever you need and then you can access it in any of your other controllers.

pass a variable across multiple controllers in rails

I wanted a variable #user to be able to accessible across all the other controllers. How do i go with this.
Here is an example
Class User
def self.current=(u)
#current_user = u
end
def self.current
#current_user
end
end
You have to set User.current = somewhere, for example in your application controller.
Then in another model or controller just call User.current
You may want to have a current_user function into your ApplicationController, something like :
def current_user
#current_user ||= User.find( session[:user_id] ) if session[:user_id].present?
end
helper_method :current_user
You may now call current_user from all your controllers and views. #Intrepidd's method is cool too.
Variables are destroyed between each call to an action.
You must re-instantiate the #user each time.
To make it clean, you could do that in a before_filter
If you mean that you want the current user (for example), you could make a method/function in your model and call that.

Resources