Double render error rails - ruby-on-rails

Not sure how its possible to get this error :
AbstractController::DoubleRenderError users#create
When in my controller I got this code :
render 'new' and return
I got the log from the bugsnag saying that I got the error at this line.
This is the create method code :
def create
back_button and return if params[:back_button]
#profile = current_user.build_profile(params[:user])
if #profile.nil? || current_user.nil? || #profile.user.nil?
sign_out
redirect_to signup_path and return
end
if #profile.new_record?
render 'new' and return
else
redirect_to more_questions_path and return
end
end
I have before filter in this controller :
before_filter :signed_in_user
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end

Give this a try:
class UsersController < ApplicationController
before_filter :signed_in_user
def create
return back_button if params[:back_button]
#profile = current_user.build_profile(params[:user])
if #profile.nil? || current_user.nil? || #profile.user.nil?
sign_out
return redirect_to signup_path
end
if #profile.new_record?
render 'new'
else
redirect_to more_questions_path
end
end
private
def signed_in_user
unless signed_in?
store_location
return redirect_to signin_url, notice: "Please sign in."
end
end
end
The reasoning behind it: x and return means x and return nil, thus returns nil. Actually, you try to short-circuit the controller action, and return redirect_to ....

The and isn't doing anything for you.
In each place where you have xxx and return, replace it with
xxx
return
For example:
redirect_to signup_path
return
That should work more like you would expect it to.

You have a render and a redirect. You have to pick one.

I suppose redirect_to signup_path is returning either nil or false, thus your and return is not being executed.
You can fix this many ways, the simplest is replace
redirect_to signup_path and return
by
redirect_to signup_path
return
Yet, I suggest you to do a bigger change. Try changing this
if #profile.nil? || current_user.nil? || #profile.user.nil?
sign_out
redirect_to signup_path and return
end
if #profile.new_record?
render 'new' and return
else
redirect_to more_questions_path and return
end
By
if #profile.nil? || current_user.nil? || #profile.user.nil?
sign_out
redirect_to signup_path
elsif #profile.new_record?
render 'new'
else
redirect_to more_questions_path
end
This way it is clear that only one path can be taken, without relying on return.

Related

Ruby on rails: previous url helper for entire application

Is there an easy way to write a helper method to always update the previously visited url in the session. I have tried the method below but the url saved is always the current one. I would like to be able to use this helper in all my controllers for redirect.
#application_controller.rb
class ApplicationController < ActionController::Base
before_filter :my_previous_url
def my_previous_url
session[:previous_url] = request.referrer
end
helper_method :my_previous_url
end
I have used it in my update method in the User controller as seen below but it always redirects to the same opened url (kind of looks like refresh was hit).
def update
if current_user.admin == true and #user.update(user_params)
redirect_to my_previous_url, notice: "Password for User #{#user.username} has Successfully been Changed."
return
elsif current_user.admin == false and #user.update(user_params)
session[:user_id] = nil
redirect_to login_path, notice: "Password for User #{#user.username} has Successfully been Changed. Please Log-In Using the New Password."
return
end
respond_to do |format|
if #user.update(user_params)
changed = true
format.html { redirect_to logout_path }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
request.referer isn't what you want here as it will be set on page redirects, thus losing the page you came from originally. I think that you have an implied requirement that it should return the last visited url which was different to the current one, is that the case? Also, i think that you would only want to set it for GET requests, otherwise you risk sending people back to the wrong url, since they will be sent back with a GET request. I'm assuming here that the purpose of this previous_url is to give people a "back" link.
Also, don't get the method to set the previous_url mixed up with the method to read it back out again.
I would do it like this:
#application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_previous_url
helper_method :previous_url
def set_previous_url
if request.method == :get && session[:previous_url] != session[:current_url]
session[:previous_url] == session[:current_url]
session[:current_url] = request.url
end
end
def previous_url
session[:previous_url]
end
end

Have same action for before submit and after submission

I want to know if it possible to have a same action, for example Users#connexion, and have for this a GET request which give the form for the connexion, and from the same action, a POST one for use the data send by the form.
Because for the moment I've a Users#connexion action, which connect a user, and an empty action Users#getconnect, which route to the form.
Connect Users#action
def connect
if usr = User.find_by(:student_number, params['student_number']) && usr.password == params['password']
session[:user] = usr
puts "connexion OK"
else
puts "Fail connexion"
end
respond_to do |format|
format.html { redirect_to users_url, notice: 'Connect!' }
end
end
getConnect
def getConnect
end
routes.rb
get '/connexion', to: 'users#getConnect'
post '/connexion', to: 'users#connect'
EDIT:
Okay so It was very simple, your answer work, shame on me...
def connect
if request.post?
if usr = User.find_by(:student_number, params['student_number']) && usr.password == params['password']
session[:user] = usr
puts "connexion OK"
else
puts "Fail connexion"
end
respond_to do |format|
format.html { redirect_to users_url, notice: 'Connect!' }
end
end
end
And yes thanks for the comment, effectively I don't need the "else" statement, the view is rendering automatically!
You can use:
def connect
if request.post?
#Something
else
#Something else
end
end

Rails: Notice error

While trying to follow a tutorial, I raised an error when I test the "Sign out" link. I checked the difference with the tutor, but I couldn't figure out why I can't do it my way and why the error occurs on this spot.
My code:
class SessionsController < ApplicationController
def create
if user = User.authenticate(params[:email], params[:password])
session[:user_id] = user.id
redirect_to(session[:intended_url] || user), notice:"Welcome back, #{user.name}"
session[:intended_url] = nil
else
flash.now[:alert] = "Invalid email/password combination! you are a failure"
render :new
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "You're now signed out!"
end
end
The correction code:
class SessionsController < ApplicationController
def new
end
def create
if user = User.authenticate(params[:email], params[:password])
session[:user_id] = user.id
flash[:notice] = "Welcome back, #{user.name}!"
redirect_to(session[:intended_url] || user)
session[:intended_url] = nil
else
flash.now[:alert] = "Invalid email/password combination!"
render :new
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "You're now signed out!"
end
end
The error that was raised:
SyntaxError in SessionsController#destroy
C:/Users/xcpro/ve2/2B3/app/controllers/sessions_controller.rb:6:
syntax error, unexpected ',', expecting keyword_end
...ession[:intended_url] || user), notice:"Welcome back, #{user... ...
^
The problem is that method redirect_to take parameters only in parentheses, however notice also should passed in it. Add parentheses around all redirect_to parameters:
redirect_to( (session[:intended_url] || user), notice: "Welcome back, #{user.name}" )
or maybe space after redirect_to would work also:
redirect_to (session[:intended_url] || user), notice: "Welcome back, #{user.name}"

using redirect and if multiple times

My question is actually fairly simple, how do I make a create action which checks if a user is logged in, and if she/he is then redirect to the dashboard instead of rendering the index page where they've got links and stuff to go to and sign up. Also why is the code below not working.
class UsersController < ApplicationController
def new
#user = User.new
end
def create
if current_user.nil?
redirect_to dplace_index_path
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end
end
end
end
Your code isn't doing what you expect because the if statements are actually nested (you want elsif with this same structure -- or see my suggested fix below). Here's what your code, when properly formatted, actually looks like:
def create
if current_user.nil?
redirect_to dplace_index_path
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end
end
end
Logically, you will never get down into the second if statement, because current_user must be nil to enter the first. Try something like this instead:
def create
if current_user
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
else
redirect_to dplace_index_path
end
end
I rearranged the code, but it should logically do what you want now. I put the "happy path" first (the current_user exists), and moved the redirect into the else statement.
General user authentication:
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to dashboard_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
Try:
def create
if current_user.blank? # .blank? will check both blank and nil
# logic when user is not logged in
redirect_to index_path
else
# logic when user is logged in
redirect_to dashboard_path
end
end
def create
redirect_to dplace_index_path unless current_user
# no need to check current_user again
#user = User.new(params[:user])
if #user.save
auto_login(#user)
redirect_to dplace_index_path
end
end

Authentication Problem - not recognizing 'else' - Ruby on rails

I can't seem to figure out what I am doing wrong here. I have implemented the Super Simple Authentication from Ryan Bates tutorial and while the login portion is functioning correctly, I can't get an error message and redirect to happen correctly for a bad login.
Ryan Bates admits in his comments he left this out but can't seem to implement his recommendation. Basically what is happening is that when someone logs in correctly it works. When a bad password is entered it does the same redirect and flashes 'successfully logged in' thought they are not. The admin links do not show (which is correct and are the links protected by the <% if admin? %>) but I need it to say 'failed login' and redirect to login path. Here is my code:
SessionsController
class SessionsController < ApplicationController
def create
if
session[:password] = params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
def destroy
reset_session
flash[:notice] = 'Successfully logged out'
redirect_to posts_path
end
end
ApplicationController
class ApplicationController < ActionController::Base
helper_method :admin?
protected
def authorize
unless admin?
flash[:error] = "unauthorized request"
redirect_to posts_path
false
end
end
def admin?
session[:password] == "123456"
end
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
#
end
You need to use Ruby's comparison operator == rather than the assignment operator =. Your create action should be:
def create
if session[:password] == params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
Edit: The problem is that nowhere in your SessionsController are you actually checking the entered password against the correct password. Change your create method to this:
def create
if params[:password] == '123456'
session[:password] = params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
It's not ideal having the password hard-coded like this and storing it in the session for use by the admin? helper method, but this is supposed to be super simple authentication.
if #YOU MISSING SOMETHING HERE WHICH Returns TRUE IF USER IS VALID
session[:password] = session[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "invalid login" #CHange if messaage for invalid login
redirect_to login_path
end
it must be
if session[:password] == params[:password]
You never have a fail condition due to:
if session[:password] = session[:password]
This will always be true. You probably want something like:
if session[:password] == 'canihazpasswrd' then
do_something_here
Edit: Refer #john's answer. :)
Try this:
def create
if session[:password] == '123456'
flash[:notice] = 'Succesfully logged in'
redirect_to home_path
else
flash[:notice] = "Incorrect Password!"
redirect_to login_path
end
end
The thing is that the tutorial you used does no user's authentication. It only checks if the login belongs to an admin, so some content will be showed.
This way you'll never have wrong login/password, just admin/non-admin.

Resources