I have some code here that is supposed to create a session upon login, and create "#current_user". However, neither of these things are working, and after 2 days of speculating, I can't figure out why.
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to login_path
flash[:success] = "Account created. You may now log in"
else
redirect_to '/signup'
flash[:warning] = "Something went wrong. Try again."
end
end
private
def user_params
params.require(:user).permit(:username, :jabber_id, :password)
end
end
Sessions controller:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:name])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
session[:session_id] = nil
redirect_to login_path
end
end
Application controller:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Related
Hello guys so what i want to do is simple.
I want a before filter to check if the current user is admin, to automatically redirect him to the admin panel even if the admin accesses the index page(e.g localhost:3000 which is the root url for normal users)
for the admin users the path is localhost:3000/admin/
I have written these blocks of code so far but cause a redirect loop
in my application_controller.rb i have this
include SessionsHelper
before_filter :admin_users?
private
def admin_users?
if current_user.admin?
redirect_to admin_path
end
end
and the current_user method is the following which is in sessionshelper.rb
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
here is users controller
class UsersController < ApplicationController
before_filter :admin_users? # application controller method
before_action :logged_in_user, only: [:index,:edit,:update] # is in Application Controller
before_action :correct_user, only: [:edit,:update]
before_action :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def edit
#user = User.find(params[:id])
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name,:email,:password,:password_confirmation)
end
# before filters
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
any clues?
The issue is next. You have put your redirect inside application_controller.rb, that all other controller inherit from, even Admin controller.
You have to do next:
remove before_filter :admin_user from your ApplicationController, and put it only where you want to check if user is admin, all controllers except admin controller.
You have redirect loop because admin controller will redirect to admin_path, when you come to admin_path.
I have created an app with simple login authentication, it is actually a twitter clone. The user logs in and access the pages, etc.
But when the user posts something from there profile. It gives an error
NoMethodError in RibbitsController#create
undefined method `id=' for nil:NilClass
The error is around line 5:
class RibbitsController < ApplicationController
def create
#ribbit = Ribbit.create(user_ribbits)
#ribbit.userid = current_user.id
if #ribbit.save
redirect_to current_user
else
flash[:error] = "Problem!"
redirect_to current_user
end
end
private
def user_ribbits
params.require(:ribbit).permit(:content, :userid)
end
end
The request given to app:
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"dwVmjDNO4GOowphGFgChMDBxBfvka+M/xSUHvJMECzwxtv4NF6OuWtiaX74NLz91OwQJ9T9+wm7yMiPQ0BLpGA==",
"ribbit"=>{"content"=>"hi. test.\r\n"},
"commit"=>"Ribbit!"}
The sessions controller:
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:userid] = user.id
redirect_to rooturl, notice: "Logged in!"
else
flash[:error] = "Wrong Username or Password."
redirect_to root_url
end
end
def destroy
session[:userid] = nil
redirect_to root_url, notice: "Logged out."
end
end
The users controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to #user, notice: "Thank you for signing up!"
else
render 'new'
end
end
def show
#user = User.find(params[:id])
#ribbit = Ribbit.new
end
private
def user_params
params.require(:user).permit(:name, :username, :email, :password, :password_confirmation, :avatar_url)
end
end
And the application controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
I would really appreciate it if you guys would help!
Thanks.
You're trying to assign current_user.idto #ribbit.userid without ensuring that current_user is set. 'current_user' would be set only if a user has been previously saved before.
Therefore, you need either to make sure that an authenticated user is trying to create a Ribbit, or if you consider the userid as a non mandatory field, you can simply change your line 5 by:
#ribbit.userid = current_user.id unless current_user.blank?
If you only want authenticated user to create Ribbits, then consider using a gem to handle authentication such as Devise. You could then use before_filter :authenticate_user! in your controller to make sure users are properly authenticated.
I keep getting a variety of error while trying to create and show errors in a simple Rails blog I'm trying to create.Let me know if you see anything obvious or if you need me to post more code as I've tried a number of things but to no avail. Thanks
The browser is giving me this error
Couldn't find User without an ID
in my "logged_in?" method which shows
def logged_in?
#current_user ||= User.find(session[:user_id])
end
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
flash[:success] = "You are logged in"
redirect_to root_path
else
render action: 'new'
flash[:error] = "There was a problem logging in. Please check your email and password"
end
end
end
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def edit
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
flash[:notice] = "You have registered, please login"
redirect_to login_path
else
render :new
end
end
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
Articles Controller
class ArticlesController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
def new
#article = Article.new
end
def index
#article = Article.all
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def show
#article = Article.find(params[:id])
end
def destroy
#article = Article.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text, :image)
end
end
Application Helper
module ApplicationHelper
def logged_in?
#current_user ||= User.find(session[:user_id])
end
end
The problem you're facing is that session[:user_id] is nil. Usually a method which sets current user is called current_user. The logged_in? is not a good name for a method setting an user instance, because one would expect that a method ending with a question mark would return a true or false. And not an user instance.
Also, setting the current user is usually done with a before_filter. Additionally, you want to skip such before filter for action where you're setting the current user (i.e the current_user doesn't exist yet)
Finally, I would rather fail gracefully, if user is not found. You can achieve this by changing your code to User.find_by_id(session[:user_id])
While the user is not loggued, session[:user_id] is nil, and so User.find(session[:user_id]) generates the error. The method should be like this:
def logged_in?
#current_user ||= User.find(session[:user_id]) if session[:user_id].present?
end
Why would the logged_in? helper method try to assign a value to #current_user? I think that is a bad logic, it should just return a boolean result without modifying such a central instance. This is a proper way to do that:
def logged_in?
#current_user.nil? ? false : true
end
The responsibility of setting the #current_user falls to a method that you should place in application_controller.rb and make it a before_action so that it's executed before any controller action is triggered, that is:
# app/controllers/applicaton_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_action :authenticate_user
# Your actions here
..
..
#
private
def authenticate_user
#current_user ||= User.find(session[:user_id]) if session[:user_id].present?
end
end
I am not able to solve this syntax error I have on permission.rb. It says it needs a extra "end" but when I do add it Safari is unable to load the page. I have tried several different methods on both files, none seem to work. Any ideas?
Error:
SyntaxError in UsersController#new
/Users/lexi87/dating/app/controllers/application_controller.rb:20: syntax error, unexpected keyword_end, expecting end-of-input
Rails.root: /Users/lexi87/dating
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:1:in `<top (required)>'
permission.rb (without the extra 'end'):
class Permission < Struct.new(:user)
def allow?(controller, action)
if user.nil?
controller == "galleries" && action.in?(%w[index show])
elsif user.admin?
true
else
controller == "galleries" && action != "destroy"
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
end
UPDATE
Here's my users_controller:
class UsersController < ApplicationController
before_filter :authorize
def new
#user = User.new
end
def profile
#profile = User.profile
end
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def index
#users = User.all
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Account updated"
redirect_to #user
authorize! :update, #user
else
render 'edit'
end
end
end
It looks like you need another end in permission.rb and you need to move one in application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end # this shouldn't be here
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
# it should be here
corrections
1.
You definetely need the end at the end of the permission.rb
2.
you do not need and end to end the private section of ApplicationController. Everything below the private keyword is considered 'private'. So you need to move the "authorize" method.
solution
So the complete code is (with moving one method into "public"):
permission.rb:
class Permission < Struct.new(:user)
def allow?(controller, action)
if user.nil?
controller == "galleries" && action.in?(%w[index show])
elsif user.admin?
true
else
controller == "galleries" && action != "destroy"
end
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery
def authorize
if !current_permission.allow?(params[:controller], params[:action])
redirect_to root_url, alert: "Not authorized."
end
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def current_permission
#current_permission || ::Permission.new(current_user)
end
end
You don't have to close the private keyword.
The end after
def current_permission
is not necessary !
I am trying to block all default methods except create and update in my users controller using declerative_authorization. But at the time I add filter_resource_access or filter_access_to into my usersController i always get "Couldn't find User without an ID". Anyone care to explain why this could be happening?
class UsersController < ApplicationController
filter_resource_access
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Account registered!"
redirect_to account_url
else
render :action => :new
end
end
def show
#user = #current_user
end
def edit
#user = #current_user
end
def update
#user = #current_user # makes our views "cleaner" and more consistent
if #user.update_attributes(params[:user])
flash[:notice] = "Account updated!"
redirect_to account_url
else
render :action => :edit
end
end
end
You should set the #user variable before the filter_access_to call with a before_filter as declarative_authorization tries to access #user when you call filter_access_to.
before_filter :set_user
filter_access_to :all
...
protected
def set_user
#user = #current_user
end
Maybe you are setting the attribute_check parameter to true in your filter_access_to call? I have a similar controller and I don't really need the before_filter.
Another thing that might be causing it is a using_access_control call in your User model.