I have a user model: :name, :email, :password
Here is my form:
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.text_field :password %>
<%= f.submit "Save" %>
<% end %>
I want to display the form without :password, when I remove the password attribute and submit the form, the fields do not update in the database. I get a rollback.
You can do something like:
object.attribute = value
object.save(:validate => false)
This will never call your validation
But remember this will never validates your email and name fields as well if they are blank.
Commenting this line in my user model fixed the issue:
validates :password, length: { minimum: 6 }
However, as noted in the comments, it is not sufficient.
A user can edit their own profile, an admin can edit their own and others profiles.
Here is a solution:
def update
#user = User.find_by_id(params[:id])
if current_user?(#user)
if #user.update_attributes(user_params)
flash[:success] = "Your profile updated"
redirect_to #user
else
render 'edit'
end
else
if #user.update_attributes(admin_params)
flash[:success] = "Others profile updated"
redirect_to #user
else
render 'admin_edit_user'
end
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
def admin_params
params.require(:user).permit(:name, :email, :password) if current_user.admin?
end
If you want to skip validations on a particular form for a particular attribute, you could do the following.
Class User
attr_accessor :skip_password_validation
validate_presence_of :password, unless: -> { skip_password_validation }
end
This creates a virtual attribute that you can set and read but won't get persisted in the database.
Then you can put a hidden field for :skip_password_validation in whatever form you want and it will skip the validations.
<%= f.hidden_field :skip_password_validation, value: true %>
You'll also have to add this param to the user_params in the controller.
Related
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.
The problem I'm facing most likely has something to do with strong parameters. The thing is when I try to edit some user information and update it, an error appears which is not related with this form. That kind of error's supposed to pop up only when signing up or logging in.
For example, here is my database. And then I click 'Edit'.
After editing some information and submitting it, the error pops up.
controllers/users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id] = #user.id
redirect_to [#user, #task], notice: "Thank you for signing up!"
else
render "new"
end
end
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to #user
else
render 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to {|format| format.js }
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
end
views/user/edit.html
<h1>Editing user</h1>
<%= form_for :user, url: #user, method: :patch do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#user.errors.count, "error") %> prohibited
this task from being saved:
</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :first_name %><br>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %><br>
<%= f.text_field :last_name %>
</p>
<p>
<%= f.submit %>
</p>
<%= link_to 'Back to List', users_path %>
<% end %>
models/user.rb
class User < ActiveRecord::Base
has_secure_password
EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :first_name, presence: true,
length: {maximum: 20}
validates :last_name, presence: true,
length: {maximum: 40}
validates :email, presence: true,
format: {with: EMAIL_REGEX},
uniqueness: {case_sensitive: false}
validates :password,
length: {within: 6..40}
has_many :tasks
end
What do I do? Can anybody help?
The problem is not with the strong params. It is due to validation you have on password.
This
validates :password,length: {within: 6..40}
should be
validates :password,length: {within: 6..40}, on: :create
Yes, the problem is in strong params. You should never permit password and password_confirmation
def user_params
params.require(:user).permit(:first_name, :last_name, :email)
end
Just remove password and password_confirmation from user_params. You wouldn't want to mass assign those values.
And this would be a very bad practice to store a plain password in database. You should store encrypted or hashed password in database; it would enhance the security and integrity of your application.
To get more information about storing an encrypted or hashed password, please take a look at this and this links.
Working through the railstutorial.org . Currently on the Update Profile page part of it. When leaving the Password and Password Confirmation fields empty, only the Password is too short error comes up, though in the tutorial screenshot Password confirmation can't be blank message is present. But, it does show up when the Password field is filled and Password Confirmation field is left empty.
edit.html.erb :
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
<%= gravatar_for #user %>
change
</div>
</div>
users_controller.rb:
.
.
.
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
.
.
.
user.rb:
class User < ActiveRecord::Base
has_secure_password
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
before_create :create_remember_token
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
Your User.rb model is out of sync with the one MHartl uses at that point in the tutorial. Specifically, notice that he has an explicit validates :password_confirmation, presence: true in addition to the validates :password, length: { minimum: 6 }. When you call #user.update_attributes, it hits these validators and, in his case, both fail, whereas in your User.rb model there is not the presence validator.
When you have the password field filled in, you're hitting validators defined in has_secure_password rather than in your model, which is why they appear then.
Make sure you include the password and password_confirmation in your allowed parameters in you controller:
private
def user_params
params.required(:user).permit(:name, :email, password,:password_confirmation)
end
EDIT:
As the other had already pointed out you miss the validation of password_confirmation
validates :password_confirmation, presence: true
What is the proper way to have a form in a partial view reference an empty model in order to handle validation properly as defined on the model. Should I instantiate a new, empty model in the partial view and pass it through to the form? Here is what I'm working with...
MODEL
class NewsletterSignup < ActiveRecord::Base
def self.columns()
#columns ||= [];
end
def self.column(name, sql_type = nil, default = nil, null = false)
columns << ActiveRecord::ConnectionAdapters::Column.new(name, default, sql_type, null)
end
def persisted?
false
end
column :first_name, :string
column :last_name, :string
column :email, :string
column :zip, :string
validates :first_name, :last_name, :email, :zip, :presence => true
validates :email, :format => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates :zip, :format => /^\d{5}$/
end
Partial View
<%
signup = newsletter_signup.new
%>
<%= simple_form_for(signup, ...) do |f| %>
<%= f.input :first_name, :label => "First Name:" %>
<%= f.input :last_name, :label => "Last Name:" %>
<%= f.input :email, :label => "Email:" %>
<%= f.input :zip, :label => "Zip:" %>
...
<% end %>
But I can't seem to instantiate a new model like this. I assume I have to reference it in the view. (Note, I'm new to rails but have a decade+ of professional software development experience, so I apologize if some of rails constructs seem foreign to me and I may just be overlooking something simple!)
If your controller looks like this
def new
Model.new
end
def create
#model = Model.new(params[:model])
if #model.save
redirect root_path, notice: "Saved"
else
render action: 'new'
end
end
def edit
Model.find(params[:id])
end
def update
if #model.update(params[:model])
redirect root_path, notice: "Updated"
else
render action: 'edit'
end
end
You can have views like:
# new.html.erb
<%= render 'form' %>
# edit.html.erb
<%= render 'form' %>
# _form.html.erb
<%= form_for #model do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
...
<% end %>