I'm using the method
has_secure_password
on my user model which i understand creates two virtual fields:
Password
Password_confirmation
and validates the precense of them, so by my side i'm doing these others validations:
validates :password , length: {minimum: 6}
validates :password_confirmation , length: {minimum: 6}
in my view i have this form:
<%= form_for :user, url:{controller: 'users', action: 'create'}, html:{class:"form-horizontal"} do |f| %>
<div class="form-group">
<%= f.label(:name, "Nombre", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:name, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:last_name, "Apellido", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:last_name, class:"form-control ") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:cellphone, "Celular", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:cellphone, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:phone, "Telefono", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:phone, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:address, "Direccion", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:address, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:email, "Correo", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.text_field(:email, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:password, "Contraseña", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.password_field(:password, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:password_confirmation, "Confirmar Contraseña", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.password_field(:password_confirmation, class:"form-control") %>
</div>
</div>
<div class="form-group ">
<%= f.label(:city_id, "Ciudad", class:"control-label col-sm-1") %>
<div class="col-sm-3">
<%= f.select(:city_id, @cities.map {|c| [c.name, c.id]}) %>
</div>
</div>
<div class="form-buttons">
<%= submit_tag("Create Section") %>
</div>
<% end %>
and the controller has these actions:
def create
@user = User.new(user_params)
if @user.save
session[:user_id] = @user.id
redirect_to controller: "users", action: "show"
else
@cities = City.all
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :last_name, :email, :address, :password, :password_confirmation, :cellphone, :city_id, :phone)
end
so when the user submmit the the form the user gets created with the encrypted password under the field password_digest and it works fine.
my actual problem its with a controller wich let the client create a new user by sending a json, this is the method for the api controller:
respond_to :json
def create
respond_with User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :last_name, :email, :address, :password, :password_confirmation, :cellphone, :city_id, :phone)
end
when i send this JSON:
var ad = {
name:"juan",
last_name:"paco",
cellphone:"1234567890",
phone:"1234567890",
address:"porche",
password:"porche",
password_confirmation:"porche",
email:"[email protected]",
city_id: 1,
};
to
localhost.com:3000/api/v1/users/create
i get :
{"errors":{"password":["can't be blank","is too short (minimum is 6 characters)"],"password_confirmation":["is too short (minimum is 6 characters)"]}}
Looks like this issue has to do with Parameter Wrapping http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html
Since your json parameters are not under a root node (and you probably have parameter wrapping turned on in config/initializers/wrap_parameters.rb), the fields are automatically being wrapped in an root with the same name as the controller (user
). Since password
is a virtual attribute and is not returned by attribute_names
it is not wrapped:
On ActiveRecord models with no :include or :exclude option set, it will only wrap the parameters returned by the class method attribute_names.
I think the correct solution here is to either specify password
in the include
list of wrap_parameters
by adding this to the top of your UsersController
wrap_parameters include: User.attribute_names + [:password]
or make the JSON request with a user
root node
var ad = {
user:
{
name:"juan",
last_name:"paco",
cellphone:"1234567890",
phone:"1234567890",
address:"porche",
password:"porche",
password_confirmation:"porche",
email:"[email protected]",
city_id: 1
}
};