Using Wicked with Devise - ruby-on-rails

It's been a nightmare trying to integrate the two.
Update:
UsersController.rb
class UserStepsController < ApplicationController
include Wicked::Wizard
steps :confirm_password
def show
render_wizard
end
def update
render_wizard
end
end
RegistrationsController (devise)
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
super
end
protected
def users_steps_path(resource)
'/user_steps'
end
end
confirm_password.html.erb (view)
<%= form_for #user, url: wizard_path do |f| %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Change Password" %>
<% end %>
routes.rb
resources :user_steps
registrations/new.html.erb (sign up)
<div class="styled email-input2">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.email_field :email, autofocus: true, placeholder: "Email", class: "email-input" %></div>
<div><%= f.text_field :username, autofocus: true, placeholder: "Username", class: "email-input" %></div>
<div><%= f.password_field :password, autocomplete: "off", placeholder: "Password", class: "email-input" %></div>
<div><%= f.password_field :password_confirmation, autocomplete: "off", placeholder: "Password confirmation", class: "email-input" %></div>
</div>
<div class="get_motivated2">
<%= f.submit "Sign up", class: "get_motivated btn-danger" %>
<% end %>
</div>
</div>
This is what I have so far, but when I sign-up with devise it just logs me in.. It doesn't go to the :confirm_password step. Not sure what I'm doing wrong here, I've followed Ryan Bates tutorial on railscasts, but he doesn't use Devise which threw me off a bit.

I assume what you want to do is: after a user fills out the sign up form (a user record is not yet created in this step), the user is redirected to a page where she confirms her password one more time before her user account is created.
When you submit your signup form to registration_path(resource_name), devise will create a new user record and log you in. The place where you should submit all user information to create an user account is in confirm_password.html.erb. Submitting the sign up form should simply store the data (this is done by wicked) and redirect the user to the password confirmation page.
Hope this helps.

Related

How i can do this when user click on buyer role it will go to homepage and when user select seller role it will go to Dashboard

This is application Controller for devise
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:role])
end
end
signup form from devise and adding role
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
This is a role code
There is a problem when user select buyer on signup page it should go the homepage , when user select seller it should go to the selled dashboard
<%= f.label :role %>
<%= f.select :role, User.roles.keys %>
Here is the submit button
<div class="actions">
<%= f.submit "Sign up", data: {turbo: false} %>
</div>
<% end %>
<%= render "devise/shared/links" %>
You didn't provide much context about what you do in your controller when a user is signed up and how you build the form. Therefore I will just assume that it is a very basic form and all attributes are nested properly in the request and that the create action follows a simple scaffolding structure.
Then you basically only need to change where to redirect the user to depending on its role after the record was created.
# in controllers/users.rb
def create
user = User.new(user_params)
if user.save
case user.role
when 'user'
redirect_to root_path
when 'seller'
redirect_to dashboard_path
end
else
render :edit
end
end

Rails5 and Devise: Login form for multiple models

I have two models: user and employee_user, how can I setup a login form to authenticate two models at the same time? I need to login form check in what model he needs to authentiate the user
ApplicationHelper
module ApplicationHelper
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
Form
<%= form_for(:user, :url => session_path(:user)) do |f| %>
<%= f.email_field :email, required: true, placeholder: "Email" %>
<%= f.password_field :password, autocomplete: :off, required: true, placeholder: "Password" %>
<%= f.submit 'ENTER', class: "btLogin" %>
<div class="infosLembrar">
<p><%= f.check_box :remember_me %> Remember me</p>
</div>
<% end %>
Someone already did it before? Thanks!
Devise has a wiki on this. Please check: How to Setup Multiple Devise User Models
Hope this helps!

RoR: Forgot Password & Sign In - in same page

I'm trying to put Forgot password field with the sign in page, but if user is not registered (and not in apps database), then it redirects to the original devise Forgot password page with errors (http://localhost:3000/users/password). How do I make the errors appear in the same page as the sign in page (http://localhost:3000/users/sign_in)?
In app/views/devise/sessions/new.html.erb file
<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.email_field :email, required: false, autofocus: true, placeholder: "Username" %>
<%= f.password_field :password, required: false, placeholder: "Password" %>
<%= f.button :submit, "Sign In", class: "btn btn-success btn-sm" %>
<div class="remember-forgot">
<div class="row">
<div class="col-md-6">
<%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
</div>
<div class="col-md-6 forgot-pass-content">
Forgot Password
</div>
</div>
</div>
<% end %>
<!-- where reset is -->
<div class="pass-reset">
<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), namespace: 'forgot', html: { method: :post }) do |f| %>
<%= f.error_notification %>
<label>Enter the email you signed up with</label>
<%= f.email_field :email, required: true, autofocus: true, placeholder: "Email" %>
<%= f.submit "Submit", class: "pass-reset-submit btn btn-success btn-sm" %>
<% end %>
</div>
So there's a javascript link where an input field will show up if a user forgets their sign in credentials.
apparently two forms for same object having same fields should not be one page, one should stay with the new page. but still i have tried your question, and following things needs to be done
1) I have to override the passwords controller for devise under user scope.
class Users::PasswordsController < Devise::PasswordsController
# GET /resource/password/new
def new
super
end
# POST /resource/password
def create
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
flash[:notice] = "sent password"
redirect_to :root
else
render "devise/sessions/new"
end
end
# GET /resource/password/edit?reset_password_token=abcdef
def edit
super
end
# PUT /resource/password
def update
super
end
protected
def after_resetting_password_path_for(resource)
super(resource)
end
# The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
super(resource_name)
end
end
then my devise/sessions/new page will look like this(you can add the logic of showing form only when one clicks he forget password button. that should be simple. just add hide class and on click remove hide class.)
Log in
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<% if devise_mapping.rememberable? -%>
<div class="field">
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
</div>
<% end -%>
<div class="actions">
<%= f.submit "Log in" %>
</div>
<% end %>
#assuming that devise_mapping has recoverable? option. you can also keep the below form in if condition
<h2>Forgot your password?</h2>
<%= form_for(resource, as: resource_name, url: password_path(resource_name), namespace: "forget", html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="actions">
<%= f.submit "Send me reset password instructions" %>
</div>
<% end %>
need to tell the routes to use my my passwords controller.
devise_for :users, controllers: {
passwords: 'users/passwords'
}
These things will result in showing the errors under the user sign in form but the path will remain http://localhost:3000/users/password. why because we are rendering the page and not redirecting. render just show the views without going to the controller action. now even if one tries to send the errors messages to the sessions controller somehow(after overriding that controller as well) somehow like this
redirect_to new_user_session_path, :messages => resource.errors
still that wont help, why because in session#new we are re initializing the resource as it is new action and all the errors would be gone.
I'm not sure if this is satisfactory to you or if this is not even close to your requirements. i tried to cover all things. i would be glad if some credible or official sources will provide even better response. that would definitely increase my knowledge as well.

Updating User Password using Devise for Omniauth in Rails 4

I'm new to Devise and I'm trying to update user password for the users who signed up through normal sign up(form) and via Omniauth(facebook,google_oauth2).
Below is my code.
Edit form:
#app/views/devise/registrations/edit.html.erb
<h2>Change Your Details</h2>
<div><b><i>View or update your Current Email and Password <%= link_to 'Click Here', '#', :id => 'email_change' %></b></i></div>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div style="color:red">Currently waiting confirmation for: <%= resource.unconfirmed_email %>. Please confirm the new email address before using it for sign in.</div>
<% end %>
<div id='display_email'><%= f.label :current_email %> <i>(this email is currently used for email alerts and sign in)</i><br />
<%= f.email_field :email, autocomplete: "off", :class => 'form-control' %> <i>(edit this field to change your email)</i></div>
<% if resource.provider.blank? %>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off", :class => 'form-control' %></div>
<% end %>
<div><%= f.label :new_password %> <i></i><br />
<%= f.password_field :password, autocomplete: "off", :class => 'form-control' %></div>
<div><%= f.label :new_password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", :class => 'form-control' %></div>
<br>
<div><%= f.submit "Update", :class => 'btn btn-lg btn-primary btn-block' %></div>
<% end %>
Update method:
#app/controllers/registrations_controller.rb
def update
# For Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
# delete field if it is blank, so it does not update
permitted_update_fields_hash = [:first_name, :last_name, :email, :primary_phone, :password, :password_confirmation]
permitted_update_fields = [:first_name, :last_name, :email, :primary_phone, :password, :password_confirmation]
puf = permitted_update_fields.length - 1
index = 0
while index <= puf
if account_update_params[permitted_update_fields_hash[index]].blank?
account_update_params.delete(permitted_update_fields[index])
end
index += 1
end
# required for settings form to submit when password is left blank
if account_update_params[:password].blank?
account_update_params.delete("password")
account_update_params.delete("password_confirmation")
end
#user = User.find(current_user.id)
if #user.update_attributes(account_update_params)
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case their password changed
sign_in #user, :bypass => true
if #user.role == "renter"
redirect_to renter_dashboard_path(resource.renter.slug)
else
redirect_to request.referer
end
else
redirect_to request.referer
end
end
Problem:
Users who signed up through facebook,google_oauth2 can't able to provide current password because they actually don't know the current password. This is because Devise generates a random password on sign up
user.password = Devise.friendly_token[0,20]
Current Solution:
Currently I'm hiding the current_password field for the users who signed up through facebook & google_oauth2(see the below image)
Question:
Is there any better alternative approach for this situation?

Updating a user model attribute through a Devise session login

I am using the Devise authentication gem for a Ruby on Rails app. When a user logs in by creating a new session I would like to update a column in my user model. What would be the best way to do this?
Is there any way to have a hidden field that updates the model?
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<% f.hidden_field :field_a, :value => 'test' %>
<div><%= f.submit "Sign in" %></div>
<% end %>
You can do this by overwriting Devise::SessionsController create method. When the user login it will just authenticate the user, it wont update user record. So there is no use of keeping the hidden field in the form
Try like this
class Users::SessionsController < Devise::SessionsController
def create
#do your update here
end
end
or else you can follow this link http://denmarkin.tumblr.com/post/5194645960/how-to-overwrite-devise-sessions-controller-in-rails-3

Resources