I use sorcery for user authentication in a rails 4.1 application. Everything works fine. But when I try to update specific attributes of the user model (which is authenticated by sorcery), I get an error that the password is blank and is too short.
Here's a snippet from the console
> user = User.last
=> # I get the user
> user.update(about_me: "I'm a user")
=> false
> user.update(about_me: "I'm a user", password: "secret")
=> true
Here's my model code
app/models/user.rb
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :password, presence: true, length: { minimum: 6 }
.....
end
My controller code
app/controllers/users_controller.rb
class UsersController < ApplicationController
.....
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to @user
flash[:notice] = "Profile successfully updated"
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:username, :name, :email, :password, :about_me)
end
end
And my update form
app/views/users/edit.html.erb
<%= form_for @user, method: :put do |f| %>
<% if @user.errors.any? %>
<div class="alert">
<p><%= pluralize(@user.errors.count, 'error') %></p>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field :username, placeholder: 'Username' %>
<%= f.text_field :name, placeholder: 'Name' %>
<%= f.email_field :email, placeholder: 'Email' %>
<%= f.text_area :about_me, placeholder: 'About me' %>
<%= f.password_field :password, placeholder: 'Password' %>
<%= f.submit 'Save Changes', class: 'button' %>
<% end %>
If I remove the password field from the form, I get errors about the password being blank and about it's length. Is this something to do with sorcery or is it something I'm missing with rails itself? Is there a better way to update let's say only the email field without affecting anything else?
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :password, presence: true, length: { minimum: 6 }, if: :new_user?
private
def new_user?
new_record?
end
end
The validation will be checked only if it's a new_record, for which we have added our own private validation method new_user?. This function will return true during your normal signups/registrations. Hence, at those signups only the password validation will be needed.
During the edit, off course the user will be an existing user / new_record? will return false. Hence the validation for password will be skipped.
2nd way:
class User < ActiveRecord::Base
attr_accessor :skip_password
validates :password, presence: true, length: { minimum: 6 }, unless: :skip_password
end
#users_controller.rb
def update
@user = User.find(params[:id])
@user.skip_password = true
if @user.update(user_params)
redirect_to @user
else
render 'edit'
end
end
Here we have added our own custom attr_accessor skip_password. If the skip_password value is set to true, then during edit/update the password validation will be skipped.
I hope both of those ways will help you :)