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.
Related
I there,
I developp a rails app and I have a problem on displaying a special path after sign-up.
I have an attribute :status for my user which is filled in in my sign-up form. If this attribute is checked (true), I would like to display payout_method_path , whereas it is false I want to redirect to root_path.
I have the following error:
AbstractController::DoubleRenderError in RegistrationsController#create
Here is my code.
Thks for help...:-)
class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(resource)
if current_user.status?
redirect_to payout_method_path
flash[:notice] = "Your account is verified before being a seller"
else
redirect_to root_path
end
end
To prevent the default redirects from being called in devise, you will need to add a return statement in your function like so:
def after_sign_up_path_for(resource)
if current_user.status?
flash[:notice] = "Your account is verified before being a seller"
redirect_to payout_method_path
else
redirect_to root_path
end
return
end
This logic would apply to any application where you had a possibility of chaining redirects.
For example (wrong way):
def my_function
if true == true
redirect_to different_path
end
redirect_to root_path
end
The above function would fail. However, adding a return after the redirect (shown below) would cause the function to halt and prevent the execution of the other redirect.
Example (right way):
def my_function
if true == true
redirect_to different_path
return
end
redirect_to root_path
end
So I'm after a simple solution which I can't seem to work out. New to rails, so trying to learn and get the basics down.
When users aren't logged in and they try and access various pages, they are redirected to /login. What I want is to stop them form being able to view the /signin page IF they are already logged in.
How can I achieve this?
Update
application_controller
def current_user
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
sessions_controller
class SessionsController < ApplicationController
layout "empty"
def create
user = User.find_by_user_name(params[:user_name])
if user && user.authenticate(params[:password])
if params[:remember_me]
cookies.permanent[:auth_token] = user.auth_token
else
cookies[:auth_token] = user.auth_token
end
flash[:success] = "You are now logged in"
redirect_to '/'
else
flash[:error] = "Invalid username or password"
redirect_to '/login'
end
end
def destroy
cookies.delete(:auth_token)
flash[:error] = "You have successfully logged out"
redirect_to '/login'
end
private
end
Add before_action for the action /login view, if you have current_user than you can do it like this
before_action :check_session, only: [:login]
def login
# login page action
end
private
def check_session
redirect_to root_path unless current_user.blank?
end
Hope that helps!
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
I'm trying to test my controllers using Capybara. I have tried numerous ways, but for some reason I can not get it to see the current_user session. I know the login works when I run my spec for it. I'm also visiting the login page before my controller test. But it always seems to redirect me back when the :logged_in function is hit.
So not sure what I'm missing?
Here's what I have..
session_controller
def create
user = User.find_by_username(params[:username])
if( user && user.authenticate(params[:password]))
user.update_attribute(:token, User.token_digest)
flash[:notice] = "Success"
session[:user_id] = user.id
session[:token] = user.token
redirect_to dashboard_index_path
else
flash[:notice] = "Failed"
flash.now.alert = "Invalid user name or password"
render "new"
end
end
application_controller
protect_from_forgery
before_filter :logged_in
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def logged_in
if !current_user
redirect_to root_url
return
end
if session[:token] != current_user.token
redirect_to root_url
end
end
products_controller_spec
it 'Should display new product form' do
user_login
visit new_product_path
response.body.should have_content("<h1>Create New Product</h1>")
end
spec_helper.rb
def user_login
visit root_path #this is new_session
fill_in "username", :with => "admin"
fill_in "password", :with => "111111"
click_button "Login"
end
Well I got it working,Not sure its politically correct way but.. instead of visiting the page, I'm just hard setting the session. In spec_helper.rb..
def user_login
user = FactoryGirl.create(:user)
session[:user_id] = user.id
session[:token] = User.token_digest
end
I'm having a problem with a notice appearing when it shouldn't. When I click a link in my app to login, it's flashing the 'Invalid username/password combination' notice, even though I haven't typed anything in. I understand why I'm getting the message - it's because when I click the link, I haven't typed in a matching username and password, so the error fires. But I'm not sure how to fix this. I want the error to appear when the user does type in the wrong combo, but not when the page first appears.
In the code, the 'user' refers to an admin, and the customer is a customer. I'm using the same login page for both types of people.
Also, what I'd really like is that when the user does type in the wrong combination, their email address will stay in the field so that they don't have to type it in again. How would I go about doing this?
Thanks!!
Here's the updated controller code:
class SessionsController < ApplicationController
skip_before_filter :authorize
def new
end
def create
user = User.find_by_email(params[:email])
customer = Customer.find_by_email(params[:email])
if user and user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to admin_url
elsif customer and customer.authenticate(params[:password])
session[:customer_id] = customer.id
redirect_to customer_path(session[:customer_id])
else
render :new, notice: "Invalid email/password combination"
end
end
def destroy
session[:user_id] = nil
session[:customer_id] = nil
redirect_to store_url, notice: "Logged out"
end
end
Set the flash notice only when login parameters where sent with the request:
# ...
else
flash[:notice] = "Invalid username/password combination" if params[:email] || params[:password]
redirect_to login_url
end
I suggest you wrap everything in if params and rerender the view instead of redirecting to preserve the email.
if params
if user ...
...
elsif ...
...
else
render :new
Try replacing your last else statement with this:
else
if params[:email] || params[:password]
flash[:notice] = "Invalid username/password combination"
redirect_to login_url
end
end
That should do the trick. In regards to your question about the email address remaining in the field when the user enters an incorrect password, check this link: here
The general gist of the solution would be to use 'render' instead of 'redirect_to' in your code to reload the page.