What does this validation do? - ruby-on-rails

I know this validation checks for the presence of an e-mail before rendering an object as valid (in this case an user)
validates :email, presence: true
But this one I have no idea what it does
validates :login, :email, presence: true

It validates both :login and :email using the PresenceValidator, same as writing:
validates :login, presence: true
validates :email, presence: true

It add a presence validation to email and login.
validates takes a list of attributes you want to validate and a hash containing the validations you want to apply. Which is handy if you want to apply the same validations to several attributes.
These are all equivalent:
validate_presence_of :email, presence: true
validate_presence_of :login, presence: true
# or
validates :email, presence: true
validates :login, presence: true
# or
validates :login, :email, presence: true

Related

How to skip multiple validation ruby on rails

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

Ruby on rails Update

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

Rails 4 Validation: where to put the allow_nil when doing an inclusion?

Are these two implementations functionally equivalent? If so, which is "better?"
# from a model
WIDGET_COLORS = %w(red yellow green)
validates :widget_color,
inclusion: {in: WIDGET_COLORS, allow_nil: true}
or
# from a model
WIDGET_COLORS = %w(red yellow green)
validates :widget_color,
inclusion: {in: WIDGET_COLORS},
allow_nil: true
UPDATE: fixed typo so example reads validates
Firstly validate and validates are different methods - it should be validates here.
validates will search the supplied hash for so-called _validates_default_keys, which is an internal array [:if, :unless, :on, :allow_blank, :allow_nil , :strict]. All the arguments passed to validates being in this array are treated as common options for all the validators attached to the model with this method. So if you do:
validates :widget_color,
inclusion: {in: WIDGET_COLORS},
uniqueness: true,
allow_nil: true
allow_nil will affect both of the validators, or is equivalent of:
validates :widget_color,
inclusion: {in: WIDGET_COLORS, allow_nil: true},
uniqueness: {allow_nil: true}
On the other hand with
validates :widget_color,
inclusion: {in: WIDGET_COLORS, allow_nil: true},
uniqueness: true
it will only affect the validator it is defined for (in this case InclusionValidator)

How to properly write in Ruby a validate only on create

I have now this validate for my User model:
validates :email,
presence: true,
uniqueness: { :case_sensitive => false }
I'd like to add :on create for the uniqueness as users are definitely allowed to update their email by putting the same email!
Should I write it this way? I'm afraid the on:create also applies to the presence:true but it should only apply to the uniqueness validation:
validates :email,
presence: true,
uniqueness: { :case_sensitive => false }, on: :create
I would like to say some logic. Email should be unique and user will be identified by his email. So while update, there is no need to put email field where user can edit the email value. You can make the email field as readonly, so that user can not change it while updating the profile.
And yes, the syntax on: :create is the nice solution for it.
yes it will applied on both you can use separate validation for that
validates :email, presence: true
validates :email, uniqueness: { :case_sensitive => false }, on: :create

MassAssignmentSecurity error while attr_accessible has been called

I'm following along with this tutorial and at one point, it tells me to
... add password and password_confirmation attributes to the User model [...] Unlike the other attributes we’ve seen so far, the password attributes will be virtual—they will only exist temporarily in memory, and will not be persisted to the database.
And
As we’ll see in Section 6.3.4, these virtual attributes are implemented automatically by has_secure_password.
My model looks like this:
class User < ActiveRecord::Base
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
has_secure_password
attr_accessible :email, :is_admin, :name, :password, :password_confirmation
validates :name, presence: true, uniqueness: true
validates :password_digest, presence: true
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: true
end
So now when I try to create a new user;
User.create(name: "Foo Bar", email: "foo#bar.net", password: "foobar", password_confirmation: "foobar")
I get the following error:
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: password, password_confirmation
Why?!
The issues seemed as though the password and password_confirmation columns were missing in the database.
As per the comment, re-migrating and restarting the server would fix this problem.

Resources