Devise edit on custom view without current_password - ruby-on-rails

I am trying to put profile edit capabilities on to a custom '/info' page without needing current_password. It only works when you enter your current_password. Without the current password no error happens but it redirects to the unsuccessful update path specified in the controller.
I have a registrations_controller that overrides the devise one:
class RegistrationsController < Devise::RegistrationsController
def info
#user = current_user
if #user
render :info
else
render file: 'public/404', status: 404, formats: [:html]
end
end
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(devise_parameter_sanitizer.for(:account_update))
else
params[:user].delete(:current_password)
#user.update_without_password(devise_parameter_sanitizer.for(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
sign_in #user, :bypass => true
redirect_to user_path(current_user)
else
redirect_to user_path(current_user)
end
end
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
protected
def after_sign_up_path_for(resource)
'/info'
end
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
end
application_controller:
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password, :password_confirmation, :image) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:name, :email, :current_password, :password, :password_confirmation, :image) }
end
routes.rb:
devise_for :users, :controllers => { :registrations => "registrations" }
devise_scope :user do
get "/info" => "registrations#info"
end
info.html.erb:
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put}) do |f| %>
<%= f.error_notification %>
<%= f.input :image %>
<%= f.submit "Update", class: "button5"%>
<% end %>

If you don't want it to require the password, you could either get rid of the if needs_password? / else code and just use update_without_password all the time -- or you could define needs_password? to always return false.
Note: your needs_password? method is defined twice in your sample code.

Related

Rails, Devise & Omniauth - problems with setup

I am trying (again) to set up authentications with Rails 4, devise and omniauth.
I tried to follow the example in this post: Rails 4, Devise, Omniauth (with multiple providers)
I have these gems installed:
gem 'devise'
gem 'omniauth-google-oauth2'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'omniauth-linkedin-oauth2'
gem 'oauth2'
I have a user model, and an authentications model.
I have:
User.rb:
has_many :authentications
def disapprove
self.approved = false
end
def approve
self.approved = true
end
SOCIALS = {
facebook: 'Facebook',
google_oauth2: 'Google',
linkedin: 'Linkedin'
}
def self.from_omniauth(auth, current_user)
authentication = Authentication.where(:provider => auth.provider,
:uid => auth.uid.to_s,
:token => auth.credentials.token,
:secret => auth.credentials.secret).first_or_initialize
authentication.profile_page = auth.info.urls.first.last unless authentication.persisted?
if authentication.user.blank?
user = current_user.nil? ? User.where('email = ?', auth['info']['email']).first : current_user
if user.blank?
user = User.new
user.skip_confirmation!
user.password = Devise.friendly_token[0, 20]
user.fetch_details(auth)
user.save
end
authentication.user = user
authentication.save
end
authentication.user
end
def fetch_details(auth)
self.first_name = auth.info.first_name
self.last_name = auth.info.last_name
self.email = auth.info.email
self.image = URI.parse(auth.info.image)
end
Authentication.rb
belongs_to :user
Routes.rb
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => 'users/omniauth_callbacks',
}
User/registrations_controller
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
def create
#user = User.new(user_params) #(params[:user])
respond_to do |format|
if resource.save
# Tell the UserMailer to send a welcome email after save
# {#user.send_admin_mail
# #user.send_user_welcome_mail}
format.html { redirect_to(profile_path(#user.profile))}
#, notice: 'We have received your registration. We will be in touch shortly.') }
#format.json { render json: root_path, status: :created, location: #user }
else
#format.html { redirect_to(root_path, alert: 'Sorry! There was a problem with your registration. Please contact us to sort it out.') }
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
# protected
# def after_sign_up_path_for(resource)
# 'subscribers/new'
# end
end
User/Omniauth_callbacks controller
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# try again following https://stackoverflow.com/questions/21249749/rails-4-devise-omniauth-with-multiple-providers
def all
user = User.from_omniauth(env['omniauth.auth'], current_user)
if user.persisted?
sign_in user
flash[:notice] = t('devise.omniauth_callbacks.success', :kind => User::SOCIALS[params[:action].to_sym])
if user.sign_in_count == 1
redirect_to profile_path(#user.profile)
else
redirect_to root_path
end
else
session['devise.user_attributes'] = user.attributes
redirect_to root_path
end
end
User::SOCIALS.each do |k, _|
alias_method k, :all
end
end
The devise/new registrations view says:
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<div class="row">
<div class="col-md-3 col-md-offset-3">
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="facebookauth">
<%= link_to "Join with Facebook", user_omniauth_authorize_path(:facebook) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="googleauth">
<%= link_to "Join with Google", user_omniauth_authorize_path(:google_oauth2) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="linkedinauth">
<%= link_to "Join with LinkedIn", user_omniauth_authorize_path(:linkedin) %>
</div>
<% end -%>
</div>
</div>
<div class="row">
<div class="col-md-12">
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
</div>
</div>
</div>
<div class="col-md-5">
<div class="emailform">
<div class="form-inputs", style="margin-left: 7%">
<%= devise_error_messages! %>
<%= f.input :first_name, :label_html => {:class => 'deviselabels'}, autofocus: true, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :last_name, :label_html => {:class => 'deviselabels'}, required: false, :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :email, :label_html => {:class => 'deviselabels'}, required: false, autofocus: false, placeholder: "Please use your work or university address", :input_html => {:maxlength => 55, :size => 40, class: 'lineitemdevise'} %>
<%= f.input :password, :label_html => {:class => 'deviselabels'}, required: false, placeholder: "Minimum 8 characters", :input_html => {:maxlength => 15, :size => 40, class: 'lineitemdevise'} %>
</div>
<div class="form-actions">
<%= f.button :submit, "Join by email", :class => "dcpb" %>
</div>
<% end %>
</div>
</div>
I have another model called profile.rb.
profile belongs_to user
Problems:
None of this works. When I click on each of the social media login links, the page just jumps to the sign up by email form.
The heroku logs error message says:
(facebook) Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-03T07:05:48.237549+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"HD3mnzmSTEw"}}
When I complete the sign up by email form with an email and password, the user name is recognised (in that the navbar says Hello , but when I go into the rails console, the user is not listed.
Also, when I click on the user name, I get an error which says that profile does not exist. The heroku logs say:
(Couldn't find Profile with 'id'=3)
Is there another step required to make the social media registrations work to create a new user?
MY NEXT ATTEMPT:
I've changed all of the above and tried again, following the approach in the Railscasts videos.
I now use a user model and an authentications model.
In the user.rb, I have:
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
authentication.rb
belongs_to :user
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do | user |
authentication.provider = auth.provider
authentication.uid = auth.uid
authentication.user.first_name = auth.first_name
authentication.user.last_name = auth.last_name
authentication.user.image = auth.info.image
end
end
Authentications_controller:
class AuthenticationsController < ApplicationController
before_action :set_authentication, only: [:destroy]
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication.destroy
respond_to do |format|
format.html { redirect_to authentications_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
#authentication = current_user.authentications.find(params[:id])
end
end
In the routes.rb, I have:
devise_for :users,
:controllers => {
:registrations => "users/registrations",
}
patch '/auth/:provider/callback' => 'authentications#create'
Omniauth.rb
require 'omniauth-facebook'
require 'omniauth-google-oauth2'
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_KEY'],
:scope => 'public_profile', info_fields: 'id,first_name,last_name,link,email',
:display => 'popup',
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
Then when I try this, I get this error:
(facebook) Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-05T06:4839+00:00 app[web.1]: {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100,"fbtrace_id":"CrvXN22Z"}}
I find the next part of the error message odd because it refers to the callbacks controller which I no longer use (the whole thing is commented out and there is no route for it).
Authentication failure! invalid_credentials: OAuth2::Error, :
2015-11-05T08:24:16.010951+00:00 app[web.1]: Processing by Devise::OmniauthCallbacksController#failure as HTML
2015-11-05T08:24:16.012648+00:00 app[web.1]: Redirected to http://www.dder.com/users/sign_in
A FURTHER ATTEMPT
I have been trying to set up devise with omniauth for more than 1.5 years now. This is my latest attempt (following the Sitepoint tutorial at sitepoint.com/rails-authentication-oauth-2-0-omniauth). I've tried to use this tutorial before and not had any success, so I've made some tweaks to try and adapt it to some aspects of other tutorials on this topic.
I now have:
user.rb
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
authentication.rb
belongs_to :user
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do | user |
authentication.provider = auth.provider
authentication.uid = auth.uid
authentication.user.first_name = auth.first_name
authentication.user.last_name = auth.last_name
authentication.user.image = auth.info.image
end
end
authentications controller
class AuthenticationsController < Devise::OmniauthCallbacksController
before_action :set_authentication, only: [:destroy]
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication.destroy
respond_to do |format|
format.html { redirect_to authentications_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
#authentication = current_user.authentications.find(params[:id])
end
end
registrations controller
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
# before_action :configure_permitted_parameters, if: :devise_controller? # Suggestion from Sitepoint tutorial - not currently implemented because not sure about the difference between this and set params.
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
def create
super
session[:omniauth] = nil unless #user.new_record?
end
# THIS IS A SUGGESTION FROM SITEPOINT TUTORIAL
# protected
# def configure_permitted_parameters
# devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
# end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
end
routes
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => "authentications"
# :omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'authentications#create'
I can check these routes with:
rake routes | grep auth
user_omniauth_authorize GET|POST /users/auth/:provider(.:format) authentications#passthru {:provider=>/facebook|linkedin|twitter|google_oauth2/}
user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) authentications#:action
GET /auth/:provider/callback(.:format) authentications#create
new registration partial in the view
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Join with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
I'm really not sure where this path is coming from. Not sure why it's named as it is.
new session partial in the view
<%- if devise_mapping.omniauthable? %>
<div class="twitterauth">
<%= link_to "Login with Twitter", user_omniauth_authorize_path(:twitter) %>
</div>
<% end -%>
Current error:
AbstractController::ActionNotFound at /users/auth/twitter/callback
The action 'twitter' could not be found for AuthenticationsController
Devise comes with an out of the box solution for integration with omniuth. You can checkout these urls:
1. https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application
This one shows integration with DigitalOcean but can be extended to others.
2. https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
This one is from devise wiki
Hope it helps
There is a gem called dom that was made exclusively to manage Devise with multiple providers. It makes things deadly simple!
Also, I think you should read these articles. I'm sure you can solve all your questions with them:
Devise OmniAuth: Overview
OmniAuth Managing multiple provaders

What does .1 mean in `../users/1/profile.1`

/What does the .1 mean in ../users/1/profile.1? In editing an associated model in a one to one relationship, such as a user has one profile; it updates and redirected to ..users/user_id/profile.# instead of ../users/user_d/profile.
In the form_for, i used form_for [:user, #profile] to cover for the namespace through nested resources, but i don't understand why the .#. In an attempt to see if the link will cause my program to break, i clicked home (to take me back to my root page, basically reloading the profile as i had programmed for a logged in user), it reverts back to ../users/user_d/profile.
Using a debugging gem i get:
--- !ruby/hash:ActionController::Parameters
action: show
controller: profiles
user_id: '1'
format: '1'
What is format: '1'? Any explanation appreciated.
Adding my Code
USER.RB
class User < ActiveRecord::Base
attr_accessor :remember_token
before_save {self.email = email.downcase }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format:{with: VALID_EMAIL_REGEX},
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
has_one :profile, dependent: :destroy
accepts_nested_attributes_for :profile
end
PROFILE.RB
class Profile < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
validates :street, :city, :state, :zipcode, presence: true
belongs_to :user
end
Their controllers
USER CONTROLLER
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def new
#user = User.new
#profile = #user.build_profile
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Welcome to the Mini Olympics"
redirect_to user_profile_path(current_user, #profile)
else
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def edit
# Commented out the code, as its redundant due to the line 'before_action :correct_user'
# #user = User.find(params[:id])
end
def update
# Commented out first line of the code, as its redundant due to the line 'before_action :correct_user'
# #user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "profile updated"
#redirect_to #user
redirect_to user_profile_path(current_user, #profile)
else
render 'edit'
end
end
def index
#users = User.paginate(page: params[:page], per_page: 15)
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(:id, :email, :password, :password_confirmation, profile_attributes: [:name,
:street, :city, :state, :zipcode] )
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user) # '#user == current_user' = 'current_user?(#user)'
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
PROFILE CONTROLLER
class ProfilesController < ApplicationController
def edit
#profile = User.find(params[:user_id]).profile
end
def show
#profile = User.find(params[:user_id]).profile
end
def update
#profile = User.find(params[:user_id]).profile
if #profile.update_attributes(profile_params)
flash[:success] = "profile updated"
redirect_to user_profile_path(current_user, #profile)
else
render 'edit'
end
end
private
def profile_params
params.require(:profile).permit(:id, :name, :street, :city, :state, :zipcode)
end
end
Profile edit form
<% provide(:title, "Edit Profile") %>
<h1>Update your profile</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for [:user, #profile] do |f| %>
<%= render 'fields', f: f %>
<%= f.submit "Save changes", class: "btn btn-primary" %>
<% end %>
</div>
</div>
APP/VIEWS/PROFILES/_FIELDS.HTML.ERB
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :street %>
<%= f.text_field :street, class: 'form-control' %>
<%= f.label :city %>
<%= f.text_field :city, class: 'form-control' %>
<%= f.label :state %>
<%= f.text_field :state, class: 'form-control' %>
<%= f.label :zipcode %>
<%= f.text_field :zipcode, class: 'form-control' %>
ROUTES FOLDER
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
resources :users do
resource :profile, only: [:show, :edit, :update ]
end
end
Usually the point following a dot at the end of a url is the format, for instance.
/users/12.html
/users/12.js
/users/12/profiles.xml
It looks like you've got a mal-formed url being generated somewhere which is passing the ID in as the format, as well as the id parameter.
That's the explanation, I'm not sure how to get rid of it without a little more information.
What does the users and profiles controllers look like in your routes file?
What does the link_to or url_for or *_url or *_path which generated this link look like?
Although my best guess is that you could just do form_for(#profile) to tidy this up. Then redirect in your create or update method to users_profiles_path(#user, #profile)
Update:
I put part of your routes file into a new rails app and got these routes
edit_user_profile GET /users/:user_id/profile/edit(.:format) profiles#edit
user_profile GET /users/:user_id/profile(.:format) profiles#show
PATCH /users/:user_id/profile(.:format) profiles#update
PUT /users/:user_id/profile(.:format) profiles#update
I missed the fact that you used resource instead of resources, so that each user has only one profile.
In the redirect, use user_profile_path(#user), you don't need to pass in the profile, the path only has one id in it, and that's the user_id.
the "dot something" at the end of a route indicates the format you want to get.
So if you type profile.json, rails will know you want json answer and will render accordingly in the controller (if this one is supported).
Other have answered about the format.
I am currently using Rails 5.1.5 and experienced similar situation. However, once I removed the instance variables that I was passing, the ids did not append to the url and you can still access them in the views.
user_profile_path(current_user, #profile)
To
user_profile_path

Rails wicked gem

I am having problems related to the links given to login and logout.
I am not using devise gem
In my code I have given the following links
<% if current_user %>
<li><%= link_to 'Logout',{:controller=>'sessions', :action=> 'destroy'}%></li>
<% else %>
<li> <%= link_to 'Signup',{:controller =>'users', :action => 'new'} %> </li>
<li> <%= link_to 'Login,{:controller =>'sessions', :action => 'new'} %> </li>
<% end %>
I am using the wicked gem which also has the following steps:
include Wicked::Wizard
steps :business, :login, :payment
If a user enters the form_for values for new method in users_controller and submits it, the user goes to the next step but the link it shows above is "Logout" i.e the user is logged in before signup.
What to do?
Pls, any solution given is appreciated
users_controller.rb:
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#user.update_attributes(user_params )
session[:user_id]= #user.id
redirect_to user_steps_path
else
render :new
end
end
private
def user_params
params.require(:user).permit( :fname, :lname, :email, :mob, :gender, :country, :state, :suburb, :postal ,:add)
end
end
user_steps_controller.rb
include Wicked::Wizard
steps :business, :login, :payment
def show
#user = current_user
render_wizard
end
def update
#user = current_user
params[:user][:current_step] = step
session[:user_id]= #user.id
#user.update_attributes(user_params )
render_wizard #user
end
private
def redirect_to_finish_wizard(options = nil)
redirect_to root_url
end
def user_params
params.require(:user).permit( :current_step,:cmpyname, :abnacn, :cmpyadd, :cmpydet,:cash, :paypal,:bsb,:usrname,:password, :password_confirmation, :selcat, :protit, :prodes)
end
end
class ApplicationController < ActionController::Base
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
end
Just check in your views if the user is logged in to show your step form:
<% if user_signed_in?%>
instead of
<% if current_user%>
You need to sign out the user after creating it, you can do something like this
if resource.save
sign_out resource # resource = #user
You might need to override devise registrations controller for that if you are using devise!
EDIT:
In your create action you are setting session for newly created user, remove this line from your create action
session[:user_id]= #user.id
Hope this helps!
Instead of checking with current_user you should check <% if session[:user_id].present? %>
It may solve your problem

Devise + CanCan: Admin manages Users

With my set up I have 2 types of Devise users Admins and Users I would like to be able to have the admins manage the users.
I have found some tutorials about this but they approach the problem from the perspective of a single User model with roles.
So far I've gotten to the point where, when I'm logged in as an admin, I can list the users, destroy the users and create new users, however, when I try to edit a user I get a blank form (as opposed to one that's populated by user information)
Any advice would be appreciated.
Below are the relevant files. Let me know if you need to see anything else.
/config/routes.rb
TestApp::Application.routes.draw do
devise_for :admins
devise_for :users
root to: 'pages#home'
# Admin Routes
if Rails.env.production?
devise_for :admins, :skip => [:registrations]
else
devise_for :admins
end
namespace :admins do
resources :users
end
authenticated :admin do
# For production because of skip registrations
get 'admins/edit' => 'devise/registrations#edit', as: :edit_admin_registration
put 'admins' => 'devise/registrations#update', as: :admin_registration
get 'admins/dashboard' => 'admins#dashboard', as: :admin_dashboard
devise_scope :admin do
get 'admins/list' => 'admins/users#index', as: :manage_users
get 'admins/users/new' => 'admins/users#new', as: :new_admins_user
get 'admins/users/:id/edit' => 'admins/users#edit', as: :edit_admins_user
post 'admins/users' => 'admins/users#create', as: :users
delete 'admins/users/:id' => 'admins/users#destroy', as: :destroy_admins_user
end
# Manage Content Routes
get '/pages/manage' => 'pages#manage', as: :manage_pages
get '/products/manage' => 'products#manage', as: :manage_products
end
authenticated :user, :admin do
get '/products' => 'products#index'
get '/pages/4' => 'products#index'
get '/gallery' => 'products#index'
end
unauthenticated do
devise_scope :users do
get '/pages/4' => 'devise/registrations#new'
get '/gallery' => 'devise/registrations#new'
end
end
resources :pages
resources :products
end
/controllers/admins_controller.rb
class AdminsController < ApplicationController
load_and_authorize_resource
def dashboard
render "admins/dashboard"
end
def index
respond_to do |format|
format.html
end
end
def destroy
#admin.destroy
redirect_to manage_admins_path
end
end
/controllers/admins/users_controller.rb
class Admins::UsersController < ApplicationController
load_and_authorize_resource
def index
#users = User.all
respond_to do |format|
format.html
end
end
def new
#resource = User.new
respond_to do |format|
format.html
end
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to manage_users_path, notice: 'User was successfully created.' }
else
format.html { render new_admin_user_path }
end
end
end
def update
#user = User.find(params[:id])
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to manage_users_path, notice: 'User was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to manage_users_path
end
# private
# def check_permissions
# authorize! :create, resource
# end
end
/views/admins/users/edit.html.haml
.input-form
%h2
Edit #{resource_name.to_s.humanize}
= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f|
= devise_error_messages!
%fieldset{id: "edit-your-account"}
.field.required
= f.label :first_name
= f.text_field :first_name, :autofocus => true
.field.required
= f.label :last_name
= f.text_field :last_name
.field.required
= f.label :company
= f.text_field :company
.field.required
= f.label :phone
= f.text_field :phone
.field.required
= f.label :email
= f.email_field :email
.field.required
= f.label :password
= f.password_field :password
%span.instructions
(leave blank if you don't want to change it)
- if devise_mapping.confirmable? && resource.pending_reconfirmation?
%br
Currently waiting confirmation for:
= resource.unconfirmed_email
.field.required
= f.label :password_confirmation
= f.password_field :password_confirmation
.field.required
= f.label :current_password
= f.password_field :current_password
%span.instructions
(we need your current password to confirm your changes)
.field
= f.submit "Update"
= link_to "Back", :back
/helpers/admins_helper.rb
module AdminsHelper
# Devise helpers for Admin::UsersController
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Looks like renaming your instance variable should do the trick. Your edit template passes the object resource to the form but the object you've loaded from the database is set to #user:
# Admins::UsersController
def edit
#user = User.find(params[:id])
end
# AdminsHelper
def resource
#resource ||= User.new
end
You could pass this instance variable to the form_for instead, or rename #user as #resource so the helper method will return the proper instance.

Rails 3 login and logout dependent on user cookies

I want my home page to show the words logout and the path link_to logout_path to show when a user is logged in.
I had this working but have just implemented a remember me radio button and the shift from using user.id to recognise the user to auth_token seems to have messed up my if and else statements. I really can't figure out what I need to change.
I have the following:
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
if params[:remember_me]
cookies.permanent[:auth_token]
else
cookies[:auth_token]
end
redirect_to root_url
else
flash.now.alert = "Invalid email or password!"
render "signup"
end
end
def destroy
cookies.delete(:auth_token)
redirect_to root_url
end
end
The Relevant area of my home page:
<div class="login">
<li><% if session[:user_id] %>
<!-- user is logged in -->
<%= link_to "Logout", logout_path %>
<% else %>
<!-- user is not logged in -->
<%= link_to "Login", login_path %>
/
<%= link_to "Sign up", signup_path %>
<% end %></li>
</div>
My User Model
class User < ActiveRecord::Base
has_secure_password
before_create { generate_token(:auth_token) }
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_length_of :email, :within => 6..50
validates_length_of :password, :within => 6..30
validates_uniqueness_of :email, :case_sensitive => false, :on => :create
validates_format_of :email, :with => /^[A-Z0-9_.%-]+#([A-Z0-9_]+\.)+[A-Z]{2,4}$/i,
:message => "must be a valid e-mail address"
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
My Application Controller:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
end
Any help people can offer really would be much appreciated as I have tried various different things in my home page and nothing seems to get it showing Logout.
Thanks

Resources