Hi Iam using devise for my authentication of the user
I have followed the various tutorials for getting the login in a popup window but Iam not successful can any one kindly tell how do it in details. I have tried various tutorials but nothing is working every thing is redirecting again in to a login page.
I am a newbie in rails Please kindly help to this.
I am unable to get the login on the same page
Here Is my new.html.erb
<%= form_for(:user, :html => {:id => 'login_form'}, :url => user_session_path, :remote => :true, :format => :json) do |f| %>
<%= f.email_field :email, :autofocus => true, :placeholder => "email", :id => 'login_email' %>
<%= f.password_field :password, :placeholder => "password", :id => 'login_password' %>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= image_submit_tag('modals/account/login_submit.png') %></div>
<% end %>
This is my headers page
<% if user_signed_in? %>
<p>Welcome <%= current_user.email %></p>
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
<% else %>
<p>You are not signed in.</p>
<%= link_to "Sign in", new_user_session_path, :remote => :true %>
<% end %>
Firstly, do you want a pop-up or a pop-over?
Pop-ups are new Windows, and are reminiscent of 90's ads, whereas pop-overs (sometimes called modals) are integrated elements in the UI, and are basically just a div on a darkened background
All Web 2.0 sites use pop-overs to enhance usability, whereas pop-ups detract from the experience :)
Pop-Overs
We have implemented the functionality you seek (click "login" at the top of this development site)
There are several things you have to get right to make this work - I'll detail them for you here:
Routes
#config/routes.rb
devise_for :users, :path => '', :controllers => {:sessions => 'sessions', :registrations => 'registrations'}, :path_names => { :sign_in => 'login', :password => 'forgot', :confirmation => 'confirm', :unlock => 'unblock', :registration => 'register', :sign_up => 'new', :sign_out => 'logout'}
First step is to get your routes sorted
Although Devise has good routing documentation, you'll need to customize your routes to include customized session
/ registration
controllers, as well as any custom paths you want
The most important part of the routes is (you need custom controllers!):
:controllers => {:sessions => 'sessions', :registrations => 'registrations'}
Controllers
Next, you need to add ajax response functionality to your sessions
and registrations
controllers. Even though Devise adds these controllers with every install, they remain hidden, and if you want to add functionality, you'll have to extend them
Here are our sessions & registrations controllers (LOTS of this code can be removed, but it works for us right now):
Session
#app/controllers/sessions_controller.rb
class SessionsController < DeviseController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
prepend_before_filter :allow_params_authentication!, :only => :create
prepend_before_filter { request.env["devise.skip_timeout"] = true }
prepend_view_path 'app/views/devise'
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_to do |format|
format.json { render :json => {}, :status => :ok }
format.html { respond_with resource, :location => after_sign_in_path_for(resource) }
end
end
# DELETE /resource/sign_out
def destroy
redirect_path = after_sign_out_path_for(resource_name)
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message :notice, :signed_out if signed_out && is_navigational_format?
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.all { head :no_content }
format.any(*navigational_formats) { redirect_to redirect_path }
end
end
protected
def sign_in_params
devise_parameter_sanitizer.sanitize(:sign_in)
end
def serialize_options(resource)
methods = resource_class.authentication_keys.dup
methods = methods.keys if methods.is_a?(Hash)
methods << :password if resource.respond_to?(:password)
{ :methods => methods, :only => [:password] }
end
def auth_options
{ :scope => resource_name, :recall => "#{controller_path}#new" }
end
end
Registration
#app/controllers/registrations_controller.rb
class RegistrationsController < DeviseController
prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]
before_filter :configure_permitted_parameters
prepend_view_path 'app/views/devise'
# GET /resource/sign_up
def new
build_resource({})
respond_with self.resource
end
# POST /resource
def create
build_resource(sign_up_params)
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_to do |format|
format.json { render :json => resource.errors, :status => :unprocessable_entity }
format.html { respond_with resource }
end
end
end
# GET /resource/edit
def edit
render :edit
end
# PUT /resource
# We need to use a copy of the resource because we don't want to change
# the current user in place.
def update
self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
if update_resource(resource, account_update_params)
if is_navigational_format?
flash_key = update_needs_confirmation?(resource, prev_unconfirmed_email) ?
:update_needs_confirmation : :updated
set_flash_message :notice, flash_key
end
sign_in resource_name, resource, :bypass => true
respond_with resource, :location => after_update_path_for(resource)
else
clean_up_passwords resource
respond_with resource
end
end
# DELETE /resource
def destroy
resource.destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed if is_navigational_format?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
def cancel
expire_session_data_after_sign_in!
redirect_to new_registration_path(resource_name)
end
protected
# Custom Fields
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name,
:email, :password, :password_confirmation)
end
end
def update_needs_confirmation?(resource, previous)
resource.respond_to?(:pending_reconfirmation?) &&
resource.pending_reconfirmation? &&
previous != resource.unconfirmed_email
end
# By default we want to require a password checks on update.
# You can overwrite this method in your own RegistrationsController.
def update_resource(resource, params)
resource.update_with_password(params)
end
# Build a devise resource passing in the session. Useful to move
# temporary session data to the newly created user.
def build_resource(hash=nil)
self.resource = resource_class.new_with_session(hash || {}, session)
end
# Signs in a user on sign up. You can overwrite this method in your own
# RegistrationsController.
def sign_up(resource_name, resource)
sign_in(resource_name, resource)
end
# The path used after sign up. You need to overwrite this method
# in your own RegistrationsController.
def after_sign_up_path_for(resource)
after_sign_in_path_for(resource)
end
# The path used after sign up for inactive accounts. You need to overwrite
# this method in your own RegistrationsController.
def after_inactive_sign_up_path_for(resource)
respond_to?(:root_path) ? root_path : "/"
end
# The default url to be used after updating a resource. You need to overwrite
# this method in your own RegistrationsController.
def after_update_path_for(resource)
signed_in_root_path(resource)
end
# Authenticates the current scope and gets the current resource from the session.
def authenticate_scope!
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
def sign_up_params
devise_parameter_sanitizer.sanitize(:sign_up)
end
def account_update_params
devise_parameter_sanitizer.sanitize(:account_update)
end
end
Forms
Once you've added the backend functionality, you have to make your forms ajax-enabled. This is pretty simple:
Login
#app/views/devise/sessions/new.html.erb
<%= form_for(devise_resource, :as => devise_resource_name, :html => {:id => 'login_form'}, :url => user_session_path, :remote => :true, :format => :json) do |f| %>
<%= f.email_field :email, :autofocus => true, :placeholder => "email", :id => 'login_email' %>
<%= f.password_field :password, :placeholder => "password", :id => 'login_password' %>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= image_submit_tag('modals/account/login_submit.png') %></div>
<% end %>
Register
#app/views/devise/registrations/new.html.erb
<%= form_for(devise_resource, :as => devise_resource_name, :html => {:id => 'register_form'}, :url => user_registration_path, :remote => :true, :format => :json) do |f| %>
<div class="name_input_container">
<div class="name_input_cell">
<%= f.text_field :first_name, :autofocus => true, :class => 'first_name', :placeholder => 'first name' %>
<div class="error"><%= devise_resource.errors[:first_name].first if devise_resource.errors[:first_name].present? %></div>
</div>
<div class="name_input_cell_right">
<%= f.text_field :last_name, :class => 'last_name', :placeholder => 'last name' %>
<div class="error"><%= devise_resource.errors[:last_name].first if devise_resource.errors[:last_name].present? %></div>
</div>
</div>
<%= f.email_field :email, :placeholder => "email" %>
<div class="error"><%= devise_resource.errors[:email].first if devise_resource.errors[:email].present? %></div>
<%= f.password_field :password, :placeholder => "password", :title => "8+ characters" %>
<div class="error"><%= devise_resource.errors[:password].first if devise_resource.errors[:password].present? %></div>
<%= f.password_field :password_confirmation, :placeholder => "confirm password" %>
<div class="error"><%= devise_resource.errors[:password_confirmation].first if devise_resource.errors[:password_confirmation].present? %></div>
<div class="option_buttons">
<div class="already_registered">
<%= link_to 'already registered?', '#', :class => 'already_registered', :id => 'already_registered', :view => 'login' %>
</div>
<%= image_submit_tag('modals/account/register_submit.png', :class => 'go') %>
<div class="clear"></div>
</div>
<% end %>
Javascript
Finally, you just need to be able to handle the responses from Ajax:
Login
//app/assets/javscripts/application.js
$(document).on('submit', '#login_form', function(e) {
//do stuff here
}).on('ajax:success', '#login_form', function(e, data, status, xhr) {
//do stuff here
}).on('ajax:error', '#login_form', function(e, data, status, xhr) {
//do stuff here
});
Register
//app/assets/javascripts/application.js
$(document).on('submit', '#register_form', function(e){
//do stuff here
}).on('ajax:success', '#register_form', function(e, data, status, xhr) {
//do stuff here
}).on('ajax:error', '#register_form', function(e, data, status, xhr) {
//do stuff here
});