sessions handling in rails when signed up - ruby-on-rails

When I log in I get sessions working, I can log out etc. But when I create an account I can't do that, the link to logging out is not there. Any suggestions?
Here is the code for logging out layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Auth</title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!--Detta kod säger bara när du loggar in ska man kunna se länkarna... du måste skriva om den så att den säger bara
när du är inloggad ELLER skapat konto visa dessa länkar-->
<div id="user_nav">
<% if current_user %>
Logged in as <%= current_user.email %> DETTA ÄR APPLICATION.HTML.ERB.
<%= link_to "Log out", log_out_path %>
<% else %>
<%= link_to "Sign up", sign_up_path %> or
<%= link_to "log in", log_in_path %>
<% end %>
</div>
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %>
<%= yield %>
</body>
</html>
Here is sessions_controller
class SessionsController < ApplicationController
#auth
#behöver new defineras? ska den vara tom? varför måste den finnas? ny session?
#är det korrekt att skriva params[:blabla] etc?
#varför kickar sessions in bara när man loggar in? och inte när man skapat konto?
def new
end
#det känns som sessions skapas bara när man loggar in.. AKA AUTHENTICATE
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to testsida_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end
Here is users controller
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to testsida_url, :notice => "Signed up!"
else
render "new"
end
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Here is application controller
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def authorize
redirect_to login_url, alert: "Not authorized" if current_user.nil?
end
end
So I dont really know why sessions is not working when creating accounts, but when logging in they work? :S

When you create a new user, you aren't creating a new session as well (or at the very least it doesn't appear like you are). The easiest fix would be to set your :user_id session variable when a new user is created.
class UsersController < ApplicationController
# new
def create
#user = User.new(user_params)
if #user.save
# Set the current user id below
session[:user_id] = #user.id
redirect_to testsida_url, :notice => "Signed up!"
else
render "new"
end
end
# user_params
end

Related

session[:user_id] is changing from nil to previous value on browser go back button

In my rails app , when I logout , in the destroy method I am setting session[:user_id]=nil. But when I press back button on the browser the session[:user_id] gets back its previous value and it is automatically showing the logged in page. Why is this happening? How do I make the session[:user_id]=nil persistent till I change it?
session_controller.rb
class SessionsController < ApplicationController
def index
end
def show
end
def new
end
def create
#user = User.find_by_email(params[:email])
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to user_posts_path
else
render 'new'
end
end
def destroy
session[:user_id] = nil
end
end
application.html.erb
<% if !(session[:user_id].nil?)%>
Logged in as <%= current_user.email %>
<%= link_to 'Log Out', session_path(current_user), :method => :delete %>
<% else %>
<% if current_page?(new_user_path) %>
<%= link_to "Log in", login_path %>
<% elsif current_page?(login_path) %>
<%= link_to "sign up",new_user_path%>
<% else %>
<%= link_to "Log in", login_path %>
<%= link_to "sign up",new_user_path%>
<% end %>
<% end %>
<%= yield %>
there is no error in the rails s console.
last message on the console.
Started DELETE "/sessions/2" for 127.0.0.1 at 2015-10-08 00:23:11 +0530
Processing by SessionsController#destroy as HTML
Parameters: {"authenticity_token"=>"B0QLdVrsV9ZgwjS/Y8qVb3ID0q9gsC2peFQAZ/0J638kUTpXcAYcg1I+ulX1UaLujr4C7NPgIann74UETMOz6w==", "id"=>"2"}
Rendered sessions/destroy.html.erb within layouts/application (0.1ms)
Completed 200 OK in 144ms (Views: 143.4ms | ActiveRecord: 0.0ms)
Use reset_session in your logout action instead. This will issue a new session identifier and declare the old one invalid and prevents other session fixation based attacks.
http://guides.rubyonrails.org/security.html#session-fixation-countermeasures
This is a run through of how to setup your SessionsController properly:
Sessions are not really like a standard crud resource where you have the full range of CRUD verbs and fetch records from the database.
From a user standpoint there are only three actions:
new - displays the login form
create - verifies the credentials and signs the user in.
destroy - logs user out by resetting the session.
Change your routes definition to treat Sessions as a singular resource:
resource :sessions, only: [:new, :create, :destroy]
Then we are going to create a helper:
module SessionsHelper
def current_user
#user ||= User.find!(session[:user_id]) if session[:user_id]
end
def user_signed_in?
!current_user.nil?
end
def can_sign_in?
user_signed_in? || current_page?(new_user_path) || current_page?(new_session_path)
end
end
This way the actual implementation of how the user is stored in the session is only in one place in your application and not spread all over your controllers and views.
Lets make sure we can call it from our controllers:
class ApplicationController < ActionController::Base
include SessionsHelper
end
Then lets remedy the controller:
class SessionsController < ApplicationController
# GET /session
def new
end
# POST /session
def create
reset_session # prevents sessions fixation!
#user = User.find_by(email: params[:email])
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to user_posts_path
else
render 'new', flash: "Invalid username or password."
end
end
# DELETE /session
def destroy
reset_session
if user_signed_in?
flash[:notice] = 'You have been signed out successfully.'
else
flash[:error] = 'You are not signed in!'
end
redirect_to root_path
end
end
application.html.erb
<%= render partial: 'sessions/actions' %>
<%= yield %>
We use a partial since the application layout tends to turn into a monster.
sessions/_actions.html.erb.
<% if user_signed_in? %>
Logged in as <%= current_user.email %>
<%= link_to 'Log Out', session_path, method: :delete %>
<% else %>
<%= link_to 'Log in', new_session_path if can_sign_in? %>
<% end %>

Empty argument - form for

I want to implement a reset password functionality so I have followed this railscast, I receive the mail with the link to redirect to an edit password page but I get an error here.
View
<h1>Reset Password</h1>
<%= form_for #user, :url => password_reset_path(params[:id]) do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
</div>
<div class="actions"><%= f.submit "Update Password" %></div>
<% end %>
The error is :First argument in form cannot contain nil or be empty
I'm assuming that #user is empty, I'm new on RoR and I don't know why I get this error
Password Controller
class PasswordResetsController < ApplicationController
def new
render :layout => false
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to :connect, :notice => "An E-mail has been send"
end
def edit
render :layout => false
#user = User.find_by_password_reset_token!(params[:id])
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password ↵
reset has expired."
elsif #user.update_attributes(params[:user])
redirect_to root_url, :notice => "Password has been reset."
else
render :edit
end
end
end
Change your def edit to
def edit
#user = User.find_by_password_reset_token!(params[:id])
render :layout => false
end
you have to add
#user = User.new
to your new method.
you have also another error for your create method. there is no user creation.
class PasswordResetsController < ApplicationController
def new
#user = User.new
render :layout => false
end
def create
#user = User.new user_params
if #user.save
# your code to render success
else
# your code to render error
end
end
private
def user_params
params.require(:user).permit(:email) # add more
end
end
This is the answer to '#user.update_attributes(params[:user])' with forbidden attributes error.
Rails 4 has new feature known as strong parameters.
Change your password controller to:
class PasswordResetsController < ApplicationController
def new
render :layout => false
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to :connect, :notice => "An E-mail has been send"
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
render :layout => false
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_sent_at < 2.hours.ago
redirect_to new_password_reset_path, :alert => "Password ↵
reset has expired."
elsif #user.update_attributes(user_params)
redirect_to root_url, :notice => "Password has been reset."
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :email_id, :password)
end
end

How do I render my basic signup/login forms on the page using AJAX rather than re-directing?

Maybe I've just been staring at this too long, but I have a basic sign-up and log-in form that I built, and want to just render them on the same page in a div rather than redirecting to a new page.
here's my controller
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to root_url, notice: "Thanks for signing up!"
else
render "new"
end
end
end
with a similar one for session
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
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid."
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
and here is the relevant part of the view of the one-page app
<div id="user">
<% if current_user %>
Logged in as <%= current_user.email %>.
<%= link_to "Log Out", logout_path, remote: true, disable_with: "Goodbye!", :class => "logout_a" %>
<% else %>
<%= link_to "Sign Up", signup_path, remote: true, disable_with: "Welcome!", :class => "signup_a" %> or
<%= link_to "Log In", login_path, remote: true, disable_with: "Welcome Back!", :class => "login_a" %>
<% end %>
</div>
<div class="render_here">
</div>
with class "render_here" being where I want to render the forms.
I've tried rendering a partial within the link_to specification, using .js.erb files in my view, and a couple of other ideas I got by googling the problem, but I think I'm overcomplicating things and missing an easy solution for AJAXifying the signup and login process.
Thanks!
you can use respond_with
class UsersController < ApplicationController
respond_to :html, :json
def new
#user = User.new
respond_with #user
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:notice] = "Thanks for signing up!"
end
respond_with #user
end
end
respond_with is smart about the formats, if request comes in html. it will respond with html respond. if request comes in json i.e via ajax. respond_with would send an json response
If it is static page,You can use
<%= render :partial => "login_form"%>
RoR Guide supplies good info on that. login_form must be saved as "_login_form.erb"
If it is dynamic page, you can send a ajax request when the link clicks and render a html form from that request and fill the div, from response data.

Rails: Why is my session not being destroyed (even after I restart my comp!)?

My sessions were working fine and dandy and then I
created a "remember me?" checkbox for the login
tried adding a mailer for registration
created a new user to see if my mailer was working
and now when I try to logout it won't let me log out even after I restart my computer! How I know this is that my nav bar has a condition for being signed in so you see the login link if you're not logged in. I've even tried deleting the cookie but it keeps reappearing everytime I refresh the page.
users#create
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
UserMailer.registration_confirmation(#user).deliver
sign_in(#user)
format.html { redirect_to #user, notice: 'User successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
navbar
<nav class="clearfix">
<% if !signed_in? %>
<%= link_to "home", root_url %>
<% else %>
<%= link_to "my profile", current_user %>
<%= link_to "edit profile", edit_user_path(current_user) %>
<%= link_to "friends", user_friends_path(current_user) %>
<% end %>
<div class="rightnav">
<% if signed_in? %>
<%= link_to "active users", users_path %>
<%= link_to "log out", signout_path, method: "delete", :id =>"logoutlink" %>
<% else %>
<%= link_to "sign up", new_user_path, :id => "signuplink" %>
<!-- Sign Up -->
<%= link_to "log in", signin_path, :id => "loginlink" %>
<!-- Log In -->
<% end %>
</div>
</nav>
sessions controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && (!params[:session][:email].blank?) && user.authenticate(params[:session][:password])
# if params[:remember_me]
# cookies.permanent[:remember_token] = user.remember_token
# else
# cookies[:remember_token] = user.remember_token
# end
sign_in user
redirect_to user_path(user)
else
flash.now[:error] = "Invalid email and/or password."
render 'new'
end
end
def destroy
sign_out
redirect_to root_url
end
end
sessions helper
module SessionsHelper
def sign_in(user)
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
end
let me know if you need any other files.
I eventually figured it out. I just changed
cookies.delete(:remember_token)
to
cookies[:remember_token] = nil

admincontroller using wrong helper for create action

I am trying to create an admin instance through my admins controller create action, but I keep getting an error that says:
ActiveRecord::RecordNotFound in AdminsController#show: Couldn't find User with id=4
The trace indicates that it is attempting to use the sessions helper (for user) instead of the appropriate adminsessions helper.
app/helpers/sessions_helper.rb:20:in `current_user'
app/helpers/sessions_helper.rb:12:in `signed_in?'
app/views/layouts/application.html.erb:13:in
app_views_layouts_application_html_erb__1013605049_93953830
I can log in correctly and the admin is created. I just think the problem has to do with the redirect_to #admin in my admins controller, though I'm not sure.
How do I set it up so that my admins controller uses the adminsessions helper instead of the sessions helper? Any help would be greatly appreciated.
adminsessions_controller.rb
class AdminsessionsController < ApplicationController
def new
#title = "Log in"
end
def show
#title = "Admin session"
end
def create
admin = Admin.authenticate(params[:adminsession][:email],
params[:adminsession][:password])
if admin.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Log in"
render 'new'
else
sign_in admin
redirect_to admin
end
end
def destroy
sign_out
redirect_to root_path
end
end
admins_controller.rb
class AdminsController < ApplicationController
def index
#user = User.all
end
def show
#admin = Admin.find(params[:id])
end
def new
#admin = Admin.new
#title = "New admin"
end
def create
#admin = Admin.new(params[:admin])
if #admin.save
sign_in #admin
flash[:success] = "Welcome admin!"
redirect_to #admin
else
#title = "New admin"
render 'new'
end
end
end
new.html.erb (form where I create new user)
<div id="signupform_new">
<%= form_for(#admin) do |f| %>
<div class="field">
<%= f.label :username %>
<%= f.text_field :name, :class => "round" %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email, :class => "round" %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password, :class => "round" %>
</div>
<div class="field">
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, :class => "round" %>
</div>
<div class="action">
<%= button_tag "", :class => "acctSubmit" %>
</div>
<% end %>
</div>
sessions_helper.rb
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def current_user?(user)
user == current_user
end
def authenticate
deny_access unless signed_in?
end
def sign_out
session[:user_id] = nil
self.current_user = nil
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end
end
adminsessions_helper.rb
module AdminsessionsHelper
def sign_in(admin)
adminsession[:admin_id] = admin.id
self.current_admin = admin
end
def signed_in?
!current_admin.nil?
end
def current_admin=(admin)
#current_admin = admin
end
def current_admin
#current_admin ||= Admin.find(adminsession[:admin_id]) if adminsession[:admin_id]
end
def current_admin?(admin)
admin == current_admin
end
def authenticate
deny_access unless signed_in?
end
def sign_out
adminsession[:admin_id] = nil
self.current_admin = nil
end
def redirect_back_or(default)
redirect_to(adminsession[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
adminsession[:return_to] = request.fullpath
end
def clear_return_to
adminsession[:return_to] = nil
end
end
All helpers are (by default) mixed in and available in all controllers. Looks like the methods you are using should be protected or private members of your controllers instead. You can make them helper methods to be available in your views, i.e. helper_method :signed_in?.
Personally I never liked the lack of namespacing with helpers anyway. I like the presenter pattern much better (see RailsCasts Pro].

Resources