Good Evening fellow coders,
I'm slowly trying to get with grips Rspec and most of my validation occurs after the user is created as you can see from the validation below, here is the entire validation section so far.
#validations for common attributes
validates :email, presence: true, on: :create, uniqueness: true,
:format => /#/
validates :password, presence: true, on: :create, length: {minimum: 6}
#validations blocks for dev
with_options :if => lambda { |o| o.role_type == "developer" } do |dev|
dev.validates :first_name, presence: true, on: :update
dev.validates :last_name, presence: true, on: :update
dev.validates :languages, presence: true, on: :update
dev.validates :dev_desc, presence: true, on: :update
dev.validates :github, presence: true, on: :update,
:format => URI::regexp(%w(http https github))
dev.validates :stackoverflow, presence: true, on: :update,
:format => URI::regexp(%w(http https stackoverflow))
dev.validates :level, presence: true, on: :update
dev.validates :street, presence: true, on: :update
dev.validates :city, presence: true, on: :update
dev.validates :state, presence: true, on: :update
dev.validates :postcode, presence: true, on: :update
end
#validations block for employer
with_options :if => lambda { |o| o.role_type == "employer" } do |e|
e.validates :company_name, presence: true, on: :update,
uniqueness: true
e.validates :employer_desc, presence: true, on: :update
e.validates :area_of_focus, presence: true, on: :update
e.validates :number_of_employees, presence: true, on: :update
e.validates :street, presence: true, on: :update
e.validates :city, presence: true, on: :update
e.validates :state, presence: true, on: :update
e.validates :postcode, presence: true, on: :update
end
Now I have my current test which is failing below:
it "should not be valid with blank firstname" do
dev.first_name = ' '
dev.should_not be_valid
end
The user is redirected to the edit page if they are not fully valid. I cannot understand why it isn't passing. I twisted it round and changed it to should which passed the test.
Could someone maybe explain why it's passing, here is the block for dev:
let(:dev) { FactoryGirl.create :dev }
Update: Here is my factory, not sure how this would effect the error:
factory :dev, class: User do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
email { Faker::Internet.email }
password "12345678"
password_confirmation "12345678"
role_type "Developer"
dev_desc "New to development but trying to help the community"
github "www.github.com"
stackoverflow "www.stackoverflow.com"
languages "Rails"
level "Junior"
street {Faker::Address.street_address}
city {Faker::Address.city}
state {Faker::Address.state}
postcode {Faker::Address.zip_code}
end
Appreciate your help trying to understand this as validation works manually after sign up.
The validations for first_name are conditional on role being "developer", but your factory sets role to be "Developer", so the validations are not being applied.
Change your validation to
dev.validates :first_name, presence: true, allow_blank: => false, on: :update
By default, presence validation allows empty values
Related
I have 2 forms.
Form 1 I have 10 fields which I am validating.
Form 2 but it only contains 2 fields.
The model is same.
What I need to do is:
To validate fields when they are submitted by forms. If I am not posting any fields it should not validate in model. If I post 5 fields it should validate 5 fields. If I post 2 fields it should validate only 2 not all of them.
So form 1 all 10 should be validated, form 2 only 2 should validate not rest of 8.
Here is my code:
validates :teacher_number, :title, :name, :gender, :location, :dob,
:contact_mobile, :contact_home, :street, :city, :state, :zip_code, :country,
presence: true
validates :teacher_number, uniqueness: {scope: :school_id}
validate :teacher_number_existance, :on => :create
validate :school_existance, :on => :create
Below is my attempt which successfully works fine but its bulk of code that somewhat a bad practice.
validates :teacher_number, presence: true, if: "teacher_number && teacher_number.blank?"
validates :title, presence: true, if: "title && title.blank?"
validates :name, presence: true, if: "name && name.blank?"
validates :gender, presence: true, if: "gender && gender.blank?"
validates :location, presence: true, if: "location && location.blank?"
validates :dob, presence: true, if: "dob && dob.blank?"
validates :contact_mobile, presence: true, if: "contact_mobile && contact_mobile.blank?"
validates :contact_home, presence: true, if: "contact_home && contact_home.blank?"
validates :street, presence: true, if: "street && street.blank?"
validates :city, presence: true, if: "city && city.blank?"
validates :state, presence: true, if: "state && state.blank?"
validates :zip_code, presence: true, if: "zip_code && zip_code.blank?"
validates :country, presence: true, if: "country && country.blank?"
validates :teacher_number, uniqueness: {scope: :school_id}, if: "teacher_number && teacher_number.blank?"
validate :teacher_number_existance, :on => :create, if: "self.teacher_number && self.teacher_number.blank?"
validate :school_existance, :on => :create, if: "self.teacher_number && self.teacher_number.blank?"
EDIT
UPDATED MY QUESTION.
I see two ways for this:
Some hidden param in form and attr_accesor in model to turn off validation.
Use save(validate: false) for save from that second form.
Next, you can do it like this
if validate_object?
validates :email, presence: true
validates :variant, presence: true
end
You can use some patterns like form object.
But you have to remember that this object will be invalid in future too.
If you want different validations of data in different circumstances, you should not be validating on the model. You should validate elsewhere: either in the view using HTML form validation, or in the controller using Rails' Strong Params.
I think you should use HTML form validation to manage this, because you're worried about the record missing attributes. Strong Params is more useful in case you are worried about people supplying forbidden values for record attributes.
Here is how you would use HTML form validation to manage this (example using HAML):
= form_for #model do |f|
= f.text_input(:teacher_number, required: true)
...all your other inputs...
= f.submit 'Submit Form'
Here is how you would use Strong Params to constrain the number of things you can get:
class ModelsController < ApplicationController
def form_action_1
Model.create(form_1_params)
end
def form_action_2
Model.create(form_2_params)
end
private
def form_1_params
# let's permit all the things you want for the first form
params.require(:model).permit(:teacher_number, :title, ...)
end
def form_2_params
# let's permit only the few things you want in the second form
params.require(:model).permit(:only, :a, :few, :things)
end
end
I'm not sure exactly what you're asking, but perhaps this approach would work. Write your validations like this:
validates :teacher_number,
:title,
:name,
:gender,
:location,
:dob,
:contact_mobile,
:contact_home,
:street,
:city,
:state,
:zip_code,
:country,
presence: true,
on: :form2
validates :teacher_number, uniqueness: {scope: :school_id}
validate :teacher_number_existance, :on => :create
validate :school_existance, :on => :create
The on: :form2 near the bottom of the first validator means the validations will only run if you explicitly ask them to run.
So in your controller action for saving form2, you would have to do this:
if valid?(:form2) && #model.save
The other validators will run when you save, as normal. Using the on: parameter of validates for your own symbols (as opposed to the built-in ones) is covered in the Rails Guide for validations, but it's easy to miss. I didn't notice it myself until recently. I hope this helps.
Finally, after so going back and forth below solution worked well for me.
before_validation :strip_validations
def strip_validations
['teacher_number', 'title', 'name', 'gender', 'location', 'dob', 'contact_mobile', 'contact_home', 'street', 'city', 'state', 'zip_code', 'country'].each do |attr|
errors.add("Teacher", {attr => " #{attr} can't be blank"}) if send(attr.to_sym) && send(attr.to_sym).blank?
end
end
I have User model, it has some validations and they work on create. But when i call any user from database as #user=User.find(1) #user.valid? it returns false. Could you help me?
class User < ActiveRecord::Base
validates :name, :surname, :username, :phone, :role, :gender, :presence => true
validates :password_confirmation, :email_confirmation, :presence => true
validates :username, :email, :uniqueness => true
validates :verified, :bulletin, :inclusion => { :in => [true, false] }
validates :password,:email, :confirmation => true
....
end
I guess you need to add on: :create param for each validations that only need to be run on create.
For example when you're doing #user.valid? I gess you don't want to check if password_confirmation is present.
So in this case it should be:
validates :password_confirmation, :email_confirmation, :presence => true, :on => :create
Hope it helps :)
There is a special validation for this use case, that the user should provide a confirmation, but the confirmation is not stored in the database
validates :email, confirmation: true, :uniqueness => true
validates :password, confirmation: true, ....
This substitutes the validation for :password_confirmation and :email_confirmation, so you need also to remove them.
See the fine rails guides http://guides.rubyonrails.org/active_record_validations.html#confirmation
I want to add a validation in my model of rails: The local team must be different the visiting team.local_team_id is an integer that represent a team and the same for visiting_team_id.This is my code:
class Match < ActiveRecord::Base
validates :mathdate, :presence => true
validate :mydate_is_date?
validates :stage, :presence => true
validates :stage, numericality: {only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 6}
validates :state, :presence => true
validates :state, numericality: {only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 3}
validates :local_team_id, :presence => true
validates :visiting_team_id, :presence => true
validates :stadium_id, :presence => true
def mydate_is_date?
errors.add(:contructiondate, 'must be a valid date') if !mathdate.is_a?(Date)
end
Hope you can help me
Thanks
You can add a validation in Rails like so:
validate :team_ids
def team_ids
# if you want to allow blank / nil values
return if local_team_id.nil? && visiting_team_id.nil?
if local_team_id == visiting_team_id
errors.add(:local_team_id, "can't be equal to visiting_team_id")
errors.add(:visiting_team_id, "can't be equal to local_team_id")
end
end
Good Afternoon All,
I'm trying to figure out how I can stop a user from leaving the edit page, including clicking on other links until the user.valid?
Does anyone know of a way to do this in the model. Just for reference here is the model currently with the validations.
#validations for common attributes
validates :email, presence: true, on: :create, uniqueness: true,
:format => /#/
validates :password, presence: true, on: :create, length: {minimum: 6}
#validations blocks for dev
with_options :if => lambda { |o| o.role_type == "developer" } do |dev|
dev.validates :first_name, presence: true, on: :update
dev.validates :last_name, presence: true, on: :update
dev.validates :LANGUAGES, presence: true, on: :update
dev.validates :dev_desc, presence: true, on: :update
dev.validates :github, presence: true, on: :update,
:format => URI::regexp(%w(http https github))
dev.validates :stackoverflow, presence: true, on: :update,
:format => URI::regexp(%w(http https stackoverflow))
dev.validates :level, presence: true, on: :update
dev.validates :street, presence: true, on: :update
dev.validates :city, presence: true, on: :update
dev.validates :state, presence: true, on: :update
dev.validates :postcode, presence: true, on: :update
end
#validations block for employer
with_options :if => lambda { |o| o.role_type == "employer" } do |e|
e.validates :company_name, presence: true, on: :update,
uniqueness: true
e.validates :employer_desc, presence: true, on: :update
e.validates :area_of_focus, presence: true, on: :update
e.validates :number_of_employees, presence: true, on: :update
e.validates :street, presence: true, on: :update
e.validates :city, presence: true, on: :update
e.validates :state, presence: true, on: :update
e.validates :postcode, presence: true, on: :update
end
Maybe a after_validation hook but I'm not to sure, would like some advise.
UPDATE: Tried using the below in the application controller but hooks to all pages, how would I only assigned the method for the user.
def check_valid
if current_user.valid? == false
render :action => :edit
else
jobs_path
end
end
One approach is that when member enters the edit page you set a variable in his session that says member_on_edit = true and you need to submit the form through JS on change of any element of the edit form and store current form state into the session.
This will enable you to put a before_filter in ApplicationController that redirects the member to the edit page and populates the form elements with data stored in session.
Once session'd form state is valid and member clicks 'submit' you can set member_on_edit = false and prevent further undue redirects to the edit form.
Ok in order to solved this, I took the idea mentioned by #dosadnizub and placed it in my application controller as such.
def check_privileges!
redirect_to "/users/edit" unless current_user.valid?
end
I then used it in the relevant controllers to stop users escaping the edit page. Haven't fully tested it but works well for now:
before_filter :check_privileges!, only: [:new, :create]
So I have interesting password validation requirements:
When a user signs up, I want them to have to type in password and confirm and be between 6..40 (GOT THIS WORKING 100%)
When a user updates their profile, the same validation rules apply (GOT THIS WORKING 100%)
When an admin adds a user, they only have to enter the password once and it should be validated (NOT WORKIG)
When an admin edits a user and the password field is blank, it shouldn't update the password, if they type something, it should be validated. (PARTIAL WORKING)
validates :password, :presence => true,
:confirmation => true,
:length => {:within => 6..40},
:unless => :force_submit
The only cases I can't cover are when an admin adds a user, it is not validated and when an admin edits a user (and types in a password) it is not validated.
the :force_submit is passed in from the admin form, so the password isn't validated. (So the case of an updating empty password works)
Any ideas/magic?
Building slightly on the accepted answer, here's the code that I used in a Rails project at work. (Note: We're using devise to handle user authentication, and devise_invitable to create new users.)
PASSWORD_FORMAT = /\A
(?=.{8,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password,
presence: true,
length: { in: Devise.password_length },
format: { with: PASSWORD_FORMAT },
confirmation: true,
on: :create
validates :password,
allow_nil: true,
length: { in: Devise.password_length },
format: { with: PASSWORD_FORMAT },
confirmation: true,
on: :update
The below seem to meet my requirements...I am actually now requiring a confirmation for all users.. (It makes the view cleaner). But on an update I am allowing blanks.
validates :password, :presence => true,
:confirmation => true,
:length => {:within => 6..40},
:on => :create
validates :password, :confirmation => true,
:length => {:within => 6..40},
:allow_blank => true,
:on => :update
this works for blank password on update action:
validates :password, :presence => true, :on => :update,
:if => lambda{ !password.nil? }
validates :password,
:confirmation => true,
:length => { :minimum => 6},
:if => lambda{ new_record? || !password.nil? }
yet another variant
validates_presence_of :password_digest
validates_length_of :password, minimum: 6, if: Proc.new { |user| user.password.present? }