I set the Devise to allow an email only registration process that sends an email with a link to confirm account by setting password.
I would like to set the firstname and lastname at the same time than password setup (and account confirmation) but I don't know how to do.
Here is my confirmation controller (working), Crafter being my standard User.
I tried Crafter.update_attributes(params[:crafter]) with no luck.
Any help would be wonderful. TY.
def update
with_unconfirmed_confirmable do
if #confirmable.has_no_password?
#confirmable.attempt_set_password(params[:crafter])
if #confirmable.valid?
#confirmable.update_attributes(params[:crafter])
do_confirm
else
do_show
#confirmable.errors.clear #so that we wont render :new
end
else
self.class.add_error_on(self, :email, :password_allready_set)
end
end
if !#confirmable.errors.empty?
render 'devise/confirmations/new' #Change this if you don't have the views on default path
end
end
def do_show
#confirmation_token = params[:confirmation_token]
#requires_password = true
self.resource = #confirmable
render 'devise/confirmations/show' #Change this if you don't have the views on default path
end
def do_confirm
#confirmable.confirm!
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, #confirmable)
end
And my "confirm account" form :
<%= form_for resource, :as => resource_name, :url => update_user_confirmation_path, :html => {:method => 'patch', class: "form-horizontal", role: "form"}, :id => 'activation-form' do |f| %>
<%= f.text_field :firstname, autofocus: true, placeholder: "Firstname", class: "form-control" %>
<%= f.text_field :lastname, placeholder: "Lastname", class: "form-control" %>
<% if #requires_password %>
<%= f.password_field :password, autofocus: true, placeholder: "Choose A Password", class: "form-control" %>
<%= f.password_field :password_confirmation, placeholder: "Confirm Password", class: "form-control" %>
<% end %>
<%= hidden_field_tag :confirmation_token,#confirmation_token %>
It's hard to tell but I'd guess you're not getting the firstname, lastname params passed to the controller.
Rails 4 uses something called strong parameters; the README there has lots of good info if you want to go beyond my example below.
In your ApplicationController you need to allow for additional params, add these lines:
app/controllers/application_controller.rb
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:firstname, :lastname, :email, :current_password, :password, :password_confirmation)
end
end
That should fix things.
In your CrafterController you could do something like this:
#confirmable.update_with_password(account_update_params)
Just do be a bit cleaner
Related
I'm new to RoR and I'm trying to create a sign-up form. When I click on 'Create my account', data does not get saved to the database. I have added resources: users to my routes file. Is there something else I'm missing?
This is my view (signup.html.erb)
Sign Up
<%= form_for #user, :url => { :action => "create" } do |f| %>
<%= f.label :emp_id,"Employee ID" %><br>
<%= f.text_field :emp_id, class: 'form-control' %><br><br>
<%= f.label :password, "Password" %><br>
<%= f.password_field :password, class: 'form-control' %><br><br>
<%= f.label :password_confirmation, "Password Confirmation" %><br>
<%= f.password_field :password_confirmation, class: 'form-control' %><br><br>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
This is my controller
class UsersController < ApplicationController
def new
#user = User.new
end
def signup
#user = User.new
end
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
render 'login'
else
render 'signup'
end
end
def user_params
params.require(:user).permit(:emp_id, :password)
end
end
You need to permit :password_confirmation
def user_params
params.require(:user).permit(:emp_id, :password, :password_confirmation)
end
And make sure there are no other validations like email presence or that will cause validations to fail
I'm using nested attributes to user adresses.
class User < ApplicationRecord
accepts_nested_attributes_for :address, update_only: :true
I'm passing the address id as hidden field at sign-in.
<%= form_for (#user), :html => {:class => 'lead-form'} do |f| %>
<%= f.email_field :email, class:'form-control', placeholder: "Email", required: true %>
<%= f.password_field :password, class:'form-control', placeholder: "Senha", required: true %>
<%= f.fields_for :address do |addresses_form| %>
<%= addresses_form.hidden_field :address_id, :value => #address.id %>
<% end %>
<%= f.submit 'Pedir meu convite', class: "button lead-form-button" %>
<% end %>
The e-mail is validate as uniqueness. So, when somebody try to sign in with an already taken e-mail the address params are passed as nil and i get the error:
NoMethodError in Users#create
undefined method `id' for nil:NilClass
Any idea how can i fix that?
Here is my controller:
def new
#user = User.new
#address = #user.build_address
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Você está dentro. Esse é seu perfil! =) "
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:id, :primeiro_nome, :sobrenome, :email, :cpf, :telefone, :sexo, :data_de_nascimento, :password, address_attributes: [:id, :logradouro, :bairro, :cidade, :uf, :complemento, :cep])
end
ps: The association is one to one. How can i call the address attributes if i don't pass as hidden.
Address belongs to user? If yes, you just call #user.address
Maybe you should try using try method:
<%= addresses_form.hidden_field :address_id, :value => #address.try(:id) %>
I'm filling out the sign up form on my site. I type in first name, last name, email, password, and password confirmation. When I click "submit", my form clears, and the console tells me the user already exists (even though it doesnt, and throws me a success message). In short: I'm trying to create a new user, and save it to my database.
See below:
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE
"users"."firstname" IS NULL LIMIT 1 (0.1ms) rollback transaction
Rendered users/new.html.erb within layouts/application (2.4ms)
Completed 200 OK in 136ms (Views: 68.4ms | ActiveRecord: 0.9ms)
See code below - cheers!
users_controller.rb
class UsersController < ApplicationController
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "You signed up successfully"
flash[:color] = "valid"
redirect_to #user
else
flash[:notice] = "Form is invalid"
flash[:color] = "invalid"
render "new"
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def show
#user = User.find(params[:id])
end
def new
end
end
user.rb
class User < ActiveRecord::Base
validates_length_of :password, :in => 6..20, :on => :create
validates :password_confirmation, presence: true, if: -> { new_record? || changes["password"] }
end
new.html.erb
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
<%= render 'shared/error_messages' %>
</br> <%= f.text_field :firstname, placeholder: 'First Name' %>
</br> <%= f.text_field :lastname, placeholder: 'Last Name' %>
</br> <%= f.text_field :email, placeholder: 'Email' %>
</br> <%= f.password_field :password, placeholder: 'Password' %>
</br> <%= f.password_field :password_confirmation, placeholder: 'Confirm Password' %>
<%= f.submit :Register %>
<% end %>
As you can see from the generated SQL, firstname is nil on your new user.
That is because this line contains typos:
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation
should be:
params.require(:user).permit(:firstname, :lastname, :email, :password, :password_confirmation
I think you are missing some params. Using devise? Try to create a new user via rails console to see what parameters are needed.
Check the strong parameters given as first_name and last_name but in form it is firstname and lastname.
I have settings form. I want make so that if password field is empty, update other attributes.
Also I'm using devise. Are there some useful methods that might help me with this?
form.html.erb
<%= form_for(#user, :url => url_for(:controller => 'settings', :action => 'update')) do |f| %>
<%= f.label :email, 'Email' %>
<%= f.email_field :email %>
<%= f.label :mobile, 'Mobile' %>
<%= f.phone_field :mobile %>
<%= f.label :current_password, "Current password" %>
<%= f.password_field :current_password %>
<%= f.label :password, "New Password" %>
<%= f.password_field :password, :autocomplete => "off" %>
<%= f.label :password_confirmation, "Confirm New Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Update" %>
<% end %>
user.rb
validates :password, length: {minimum: 4}, on: :update, allow_blank: true
settings_controller.rb
def update
#user = current_user
if #user.update_attributes(user_params)
sign_in(#user, :bypass => true)
flash[:success] = "Settings were successfully updated"
respond_to do |format|
format.html {redirect_to :action=> :show}
end
else
flash[:fail] = "Settings **was not updated**"
respond_to do |format|
format.html {render :action => :show }
end
end
end
Use this:
def update
# For Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
# For Rails 3
# account_update_params = params[:user]
# 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 his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
This is shameless copy-paste from devise wiki, it contains a lot of useful information that you can refer to - wiki
I am also using devise and in the admin namespace having a users_controller inherited from application_controller, as I wanted to keep the admin and user section separate.
The following thing worked for me.
In the User model
validates :password, :password_confirmation, presence: true, on: :create
In update action of the controller
def update
# .....
#user.update_without_password(users_params)
# ......
end
I'm not sure how to validate the confirm password element, this code seems to work, but the validates confirmation of password doesn't seem to compare the passwords as expected, just need a hand getting used to Rails 4's new ways.
Sign Up View:
Sign Up
<%= form_for #user 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 %>
<%= f.text_field :email, class: "form-control", autofocus: "", required: "", placeholder: "Email address" %>
<%= f.password_field :password, class: "form-control", required: "", placeholder: "Password" %>
<%= f.password_field :password_confirmation, class: "form-control", required: "", placeholder: "Confirm Password" %><br/>
<p class="button"><%= submit_tag "Register", class: "btn btn-lg btn-primary btn-block" %></p>
<% end %>
</div>
Users Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :passord_confirmation, :salt, :encrypted_password)
end
end
Users Model:
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_presence_of :password, on: :create
validates :password, confirmation: :true
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
private
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
It looks like your model's password confirmation may be off, unless you have your own private method confirmation
Try changing your model from validates :password, confirmation: :true to validates_confirmation_of :password
The API has some examples as well.
You need to make the password and password_confirmation accessible. For example:
attr_accessor :password
attr_accessible :password, :password_confirmation
validates :password, :presence => true,
:confirmation => true
Try adding that, and see if it makes a difference.