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.
Related
I got this error today when I tried to use some helper methods for the users controller:
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and
at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need
to do something like "redirect_to(...) and return".)
I put this following helpers in application_controller.rb :
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def log_in_first
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login") and return
end
end
def correct_user?
if !(current_user.id.to_s==params[:id])
session[:error]="You have no right to do this operation."
redirect_to "/"
return
end
end
end
and here is the user_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
log_in_first
#user = User.find_by id: params[:id]
correct_user?
if #user
render 'show'
else
redirect_to '/login'
end
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end
As you can see I tried to use both return and and return in log_in_first and correct_user?to fix the problem but it still doesn't work. Does anyone have any ideas?
The problem is in the show action, log_in_first redirects then the show action does whatever it wants, which is redirect or render. This is causing the error.
A better solution is to use before_action for your authentication and authorization and just let the user controller actions do their thing. Something like the below.
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def authenticate_user!
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login")
end
end
def authorize_user!
unless current_user&.id.to_s==params[:id]
session[:error]="You have no right to do this operation."
redirect_to "/"
end
end
end
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:show]
before_action :authorize_user!, only: [:show]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
#user = User.find_by id: params[:id]
render 'show'
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end
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 have a simple user model with an edit page. Currently you can change your email and your password (with a password confirmation) but I don't currently require you to type your password again before changing any of that information.
I have a before filter that requires you to be logged in as well as a before filter to ensure you can only edit your own profile. However, in the case of public computers, I would like to re-authenticate a user by making them type their password.
I am using sorcery to back my authentication. How would I go about doing this. I don't see any methods for checking the password after being logged in. Below is my current users_controller
class UsersController < ApplicationController
before_filter :require_login, :only => [ :edit, :update ]
before_filter :correct_user, :only => [ :edit, :update ]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to root_url, :notice => "Signed up!"
login_user(#user)
else
render :new
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to root_url
else
render 'edit'
end
end
private
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user == #user
end
end
I've opened an issue on Sorcery's github page. It sounds like the creator will be opening a method called validate_credentials() in the future.
Source: https://github.com/NoamB/sorcery/issues/34#issuecomment-2108845