form_for validation it doesn't work - ruby-on-rails

I have the following form_for to reset password.
<% provide(:title, "Reiniciar Password") %>
<%= form_for(#user, :url => password_reset_path(params[:id]) ) do |f| %>
<%= render 'shared/error_messages'%>
<div class="row">
<div class="span4">
&nbsp
</div>
<div class="span4" id="login-box">
<div id="login-controls">
<%= link_to(image_tag("logo.png"), root_path) %>
<br>
<br>
<%= f.password_field :password, :placeholder => "Contrasena", :tabindex => 1, :style => "height:25px;" %>
<%= f.password_field :password_confirmation, :placeholder => "Contrasena", :tabindex => 2, :style => "height:25px;" %>
<%= f.button "<i class=\"icon-lock icon-white\"></i> Actualizar Password".html_safe, :tabindex => 2, class: "btn btn-warning", :style => "width:220px;margin-bottom:5px;" %>
<% end %>
</div>
</div>
<div class="span4">
</div>
</div>
everything works perfect, exect the validations, if you press the buttom with out type anything on the password and password_confirmation field, the controller reset the password with a blank password. In my model I have the validation for the password and password confirmation and it works when you create a new user, but I don't know why in this form for reset the password it doesn't work.
Here is the model
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }, confirmation: true, unless: Proc.new { |a| !a.new_record? && a.password.blank? }
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64
self.password_reset_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def reset_password_token
self.password_reset_token = nil
self.password_reset_at = nil
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Thank for your help.
UPDATE
here is the controler
class PasswordResetsController < ApplicationController
layout "sessions"
def new
end
def create
user = User.find_by_email!(params[:password_resets][:email] )
user.send_password_reset if user
redirect_to root_url, :notice => "Las instrucciones para reestrablecer la contrasena fueron enviadas."
end
def edit
#user = User.find_by_password_reset_token!(params[:id])
end
def update
#user = User.find_by_password_reset_token!(params[:id])
if #user.password_reset_at < (2.hours.ago).to_date
redirect_to new_password_reset_path, :alert => "El link para actualizar la contrasena ha expirado."
elsif #user.update_attributes(params[:user])
#user.reset_password_token
redirect_to root_url, :notice => "La contrasena ha sido cambiada."
else
render :edit
end
end
end

Ok, I think I found the cause of your problem :
validates :password, presence: true, length: { minimum: 6 }, confirmation: true, unless: Proc.new { |a| !a.new_record? && a.password.blank? }
This line skips the validation if the password is blank, so this is why your user is being saved without any password

I think your proc skips password validation in case of update:
validates :password, presence: true, length: { minimum: 6 }, confirmation: true,
unless: Proc.new { |a| !a.new_record? && a.password.blank? }
would validate unless the record is not new (update) and the password is blank (did not submit anything in the field). Can you try commenting out the proc and see what happens?
e.g.
validates :password, presence: true, length: { minimum: 6 }, confirmation: true

Guys the problem was on the model. Here is the new validation.
validates :password, presence: true, length: { minimum: 6 }, confirmation: true, unless: Proc.new { |a| !a.new_record? && a.password.blank? && a.password_reset_token.blank? }
Thanks for your help and your time!

It could be your Proc Block which checks if the model is not a new record and if the password is empty. In this case the validation does not happen.
unless: Proc.new { |a| !a.new_record? && a.password.blank? }
So if you have a already created User:
!a.new_record? = true
and since the password is not saved directly but as a crypted password (password_digest) will also be nil thus:
a.password.blank? = true
So editing an existing user with this validation will not validate the password / password_confirm
At least I think so ;)
Maybe you can change it to:
validates :password, presence: true, length: { minimum: 6 }, confirmation: true, :if => :password?

Related

impossible to encrypt a password in a multi-step form with bcrypt

I'm a beginner in ruby on rails and I have a problem encrypting a password in my registration form. I installed the bcrypt gem but I don't understand why the form doesn't work...
my form model :
module Wizard
module User
STEPS = %w(step1 step2 step3).freeze
class Base
include ActiveModel::Model
include ActiveModel::SecurePassword
attr_accessor :user
has_secure_password
delegate *::User.attribute_names.map { |attr| [attr, "#{attr}="] }.flatten, to: :user
def initialize(user_attributes)
#user = ::User.new(user_attributes)
end
end
class Step1 < Base
validates :firstName, presence: {
message: 'Un prénom doit être renseigné'
}, length: { maximum: 50,
too_long: '50 caractères maximum pour le prénom' }
validates :lastName, presence: {
message: 'Un nom doit être renseigné'
}, length: { maximum: 50,
too_long: '50 caractères maximum pour le nom' }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255,
too_long: '255 caractères maximum pour l\'adresse mail' },
format: { with: VALID_EMAIL_REGEX,
message: 'Vous devez saisir une adresse mail valide' }
end
class Step2 < Step1
validates :password, presence: true, length: { in: 8..15 }, length: { in: 8..15 }
end
class Step3 < Step2
validates :school, presence: true
validates :typeOfTeacher, presence: true
validates :yearsOfExperience, presence: true
end
end
end
My model User.rb :
class User < ApplicationRecord
validates :firstName, presence: true, length: { maximum: 50 }
validates :lastName, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: true
has_secure_password
validates :password, presence: true
validates :school, presence: true
validates :typeOfTeacher, presence: true
validates :yearsOfExperience, presence: true
end
My controller :
When saving the user in my create function. The registration stops because of the password. I think I'm using wrong has_secure_password.
class WizardsController < ApplicationController
before_action :load_user_wizard, except: %i(validate_step)
def validate_step
current_step = params[:current_step]
#user_wizard = wizard_user_for_step(current_step)
#user_wizard.user.attributes = user_wizard_params
session[:user_attributes] = #user_wizard.user.attributes
if #user_wizard.valid?
next_step = wizard_user_next_step(current_step)
create and return unless next_step
redirect_to action: next_step
else
render current_step
end
end
def create
if #user_wizard.user.save
session[:user_attributes] = nil
redirect_to letsgo_path
else
redirect_to({ action: Wizard::User::STEPS.first } )
end
end
private
def load_user_wizard
#user_wizard = wizard_user_for_step(action_name)
end
def wizard_user_next_step(step)
Wizard::User::STEPS[Wizard::User::STEPS.index(step) + 1]
end
def wizard_user_for_step(step)
raise InvalidStep unless step.in?(Wizard::User::STEPS)
"Wizard::User::#{step.camelize}".constantize.new(session[:user_attributes])
end
def user_wizard_params
params.require(:user_wizard).permit(:firstName, :lastName, :email, :password, :password_confirmation, :school, :typeOfTeacher, :yearsOfExperience)
end
class InvalidStep < StandardError; end
end
My view :
<div class="div_Signup">
<div class="div_SignupBlock">
<%= render 'navbarSignup' %>
<div class="div_SignupBlockInt">
<div class="div_SignupText">
Inscription
</div>
<div class="div_SignupTextName">
Choisissez un mot de passe
</div>
<div class="div_SignupForm">
<%= form_for #user_wizard, as: :user_wizard, url: validate_step_wizard_path do |f| %>
<%= hidden_field_tag :current_step, 'step2' %>
<div class="div_SignupInputPassword">
<%= f.password_field :password, placeholder: 'Mot de passe', :class => field_class(#user_wizard, :password) %>
<% #user_wizard.errors[:password].each do |message| %>
<p style="color: red;"><%= message %></p>
<% end %>
</div>
<div class="div_SignupInputPasswordConfirmation">
<%= f.password_field :password_confirmation, placeholder: 'Confirmation du mot de passe', class: 'input_Signup' %>
</div>
</div>
<%= f.submit 'Suivant', class: 'button_Signup' %>
<% end %>
</div>
<footer class="footer_Signup">
<%= render 'footerSignup2' %>
</footer>
</div>
</div>
When I test my form when entering a password, I get error messages that show that the password cannot be empty, and the password confirmation field does not work.
However, I see that the password has been encrypted.
Thanks !!!

Validation doesn't work as expected for related models in Rails 4?

I use one form to enter data for two models. When I save parent model (Tenant) the child model (User) also gets saved, but only if I don't validate tenant_id in User model. If I do validates :tenant_id, presence: true in User model then validation error "Users tenant can't be blank" is displayed. Any ideas why?
Tenant model:
class Tenant < ActiveRecord::Base
has_many :users, dependent: :destroy, inverse_of: :tenant
accepts_nested_attributes_for :users
before_validation do
self.status = 0
self.name = name_orig.upcase
email.downcase!
end
validates :name_orig, presence: true, length: { maximum: 255 }
validates :name, uniqueness: { case_sensitive: false }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :status, presence: true
end
User model:
class User < ActiveRecord::Base
belongs_to :tenant, inverse_of: :users
validates_presence_of :tenant
before_validation do
self.status = 0
self.email = email.downcase
end
VALID_USERNAME_REGEX = /\A\w+\s?\w*\z/i
validates :name, presence: true, length: { maximum: 50 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
validates :tenant_id, presence: true
validates :status, presence: true
end
Tenant controller:
class TenantsController < ApplicationController
def new
#tenant = Tenant.new
#tenant.users.build
end
def create
#tenant = Tenant.new(tenant_params)
#tenant.save
if #tenant.save
flash[:success] = "Welcome!"
redirect_to #tenant # redirects to tenant profile
else
render 'new'
end
end
private
def tenant_params
params.require(:tenant).permit(:name_orig, :email,
users_attributes: [:name, :email, :password, :password_confirmation])
end
end
Signup form:
<%= form_for(#tenant) do |f| %>
<%= render 'shared/tenant_error_messages' %>
<%= f.label :name_orig, "Company name" %>
<%= f.text_field :name_orig, class: 'form-control' %>
<%= f.label :email, "Company e-mail" %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.fields_for(:users) do |u| %>
<%= u.label :name, "User name" %>
<%= u.text_field :name, class: 'form-control' %>
<%= u.label :email, "User e-mail" %>
<%= u.email_field :email, class: 'form-control' %>
<%= u.label :password, "Password" %>
<%= u.password_field :password, class: 'form-control' %>
<%= u.label :password_confirmation, "Password confirmation" %>
<%= u.password_field :password_confirmation, class: 'form-control' %>
<% end %>
<%= f.submit "Save", class: "btn btn-primary" %>
<% end %>
Since you are using nested attributes and saving both models at the same time, you cannot validate tenant_id for user since they will be persisted in a transaction.
Because tenant is not persisted, it does not yet have an id. Since it does not have an id, there cannot be tenant_id for user.
In this case validating tenant_id is pointless, because you cannot persist a user without tenant since user is being built on top of tenant. So if your user will be persisted, then a corresponding tenant will also be present.
In the case you mentioned, where users can sign up on an independent form -
To validate that a tenant will be associated in the create action use:
tenant = Tenant.find_by(params[:tenant_id])
user = tenant.users.build(user_params)
instead of
user = User.new(user_params)
This way you will not have any orphan children

undefined method `name' for nil:NilClass

I have 2 id's stored in the database. I have not touched 'spec' folder. but still localhost:3000/users/1 is showing this error.
undefined method `name' for nil:NilClass
Extracted source (around line #1):
1: <%= #user.name %>, <%= #user.email %>
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
end
end
show.html.erb
<%= #user.name %>, <%= #user.email %>
models - > users.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
end
Edit show.html.erb Like bellow:
<%- if #user.present? %>
<%= #user.name %>, <%= #user.email %>
<%end%>
The issue is arise due to #user is nil. So yu should check either the object of user is nil or not. Then Process the object as per your requirements.

cant sort active records

I am a noobie and I am trying to simply get all the records in the database and display them in alphabetical order. Whenever I display the index page the records are always sorted in descending by their id. I used the console to try calling EvalTest.order("name") and again I kept getting the records sorted by their id in descending order instead of by name. Do I need to add an index on the name column to sort by it? This seems like the answer should be so easy but I can't seem to figure it out...
Here is my code:
User Model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :eval_tests
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
after_validation { self.errors.messages.delete(:password_digest) }
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Eval_Test Model:
class EvalTest < ActiveRecord::Base
attr_accessible :description, :name
belongs_to :user
validates :user_id, presence: true
validates :name, presence: true
validates :description, presence: true, length: { maximum: 350 }
default_scope order: 'eval_tests.created_at DESC'
end
EvalTest Controller:
class EvalTestsController < ApplicationController
def show
#eval_test = EvalTest.find(params[:id])
end
def new
#eval_test = EvalTest.new
end
def index
#eval_tests = EvalTest.order("name")
end
def create
#eval_test = current_user.eval_tests.build(params[:eval_test])
if #eval_test.save
flash[:success] = "Nouveau test cree!"
redirect_to #eval_test
else
render 'new'
end
end
end
Evaluation Test index.html.erb:
<% provide(:title, 'Index des tests') %>
<h1>Index des tests</h1>
<ul class="eval_tests">
<% #eval_tests.each do |eval_test| %>
<li>
<%= link_to eval_test.name, eval_test %>
</li>
<% end %>
</ul>
This is happening because you have used default scope in your model. Try
#eval_tests = EvalTest.reorder("name")
This should solve your issue.

trying to find an user by email an get "Called id for nil"

Hi I'm working on a reset password action. But after click the button I get this error:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
Here is my password_reset_controller
class PasswordResetsController < ApplicationController
layout "sessions"
def new
end
def create
user = User.find_by_email(params[:email])
user.send_password_reset if user
redirect_to root_url, :notice => "#{user.id}Las instrucciones para reestrablecer la contrasena fueron enviadas."
end
end
and Here is my user model
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64
self.password_reset_at = Time.zone.now
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
this is the view:
<% provide(:title, "Reiniciar Password") %>
<div class="row">
<div class="span4">
&nbsp
</div>
<div class="span4" id="login-box">
<div id="login-controls">
<%= link_to(image_tag("logo.png"), root_path) %>
<br>
<br>
<%= form_for(:password_resets, url: password_resets_path) do |f| %>
<%= f.text_field :email, :placeholder => "Correo Electronico", :tabindex => 1, :style => "height:25px;" %>
<%= f.button "<i class=\"icon-lock icon-white\"></i> Reiniciar Password".html_safe, :tabindex => 2, class: "btn btn-warning", :style => "width:220px;margin-bottom:5px;" %>
<% end %>
</div>
</div>
<div class="span4">
</div>
</div>
I don't understan why I can't find the user; I try to do the same at rails console and I can find the user by email, but I can generate the password_reset_token.
Please I appreciate your help.
Thanks
use params[:password_resets][:email]
Please do User.all and see. check on which user record you invoked the password_reset_token method
This means that there is no user in your database with this email.
Use,
user = User.find_by_email!(params[:email])
method with a bang (!) will trigger an exception. find_by_email returns a nil object if the email was not found

Resources