Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Validate only on create, or on update when field is not blank

How can I restrict a Rails validation to check only on create OR when the field isn't blank? I'm creating a user settings page for an app I'm working on and the problem is that, when updating using the parameters provided by the form, the settings will only save when both a password and password confirmation are present. I would like these password fields to validate on create no matter what, but only on update when they are provided.

like image 836
Jamie Avatar asked Jun 18 '14 07:06

Jamie


4 Answers

If you want to allow blank values use: allow_blank with validates.

class Topic < ActiveRecord::Base
  validates :title, length: { is: 5 }, allow_blank: true
end

If you want to validate only on create, use on with validates.

class Topic < ActiveRecord::Base
  validates :email, uniqueness: true, on: :create
end

To cover your case:

class Topic
  validates :email, presence: true, if: :should_validate?

  def should_validate?
    new_record? || email.present?
  end
end
like image 77
cristian Avatar answered Nov 17 '22 14:11

cristian


This turned out to be a little simpler than I thought. I changed the form input names from password and password_confirmation to new_password and new_password_confirmation. I added temporary accessors for these values in my model using the following line:

attr_accessor :new_password, :new_password_confirmation

I implemented a password_changed? method defined as follows:

def password_changed?
    !new_password.blank?
end

Finally, I changed my validations to:

validates :new_password, presence: true, confirmation: true, length: { in: 6..20 }, on: :create
validates :new_password, presence: true, confirmation: true, length: { in: 6..20 }, on: :update, if: :password_changed?
validates :new_password_confirmation, presence: true, on: :create
validates :new_password_confirmation, presence: true, on: :update, if: :password_changed?

I'm positive there's a better way to do this (this isn't very DRY) but for now, it works. Improved answers would still be very much appreciated.

like image 36
Jamie Avatar answered Nov 17 '22 15:11

Jamie


It is not necessary to change field names, will be enough to replace :password_changed? to :password_digest_changed? in your code.

validates :password, presence: true, confirmation: true, length: { in: 6..20 }, on: :create
validates :password, presence: true, confirmation: true, length: { in: 6..20 }, on: :update, if: :password_digest_changed?
validates :password_confirmation, presence: true, on: :create
validates :password_confirmation, presence: true, on: :update, if: :password_digest_changed?
like image 12
Anton Ruban Avatar answered Nov 17 '22 15:11

Anton Ruban


Please try

validates :<attributes>, if: Proc.new{|obj| obj.new_record? || !obj.<attribute>.blank? }

or add custom method names instead of attribute name.

like image 7
Sanket Avatar answered Nov 17 '22 14:11

Sanket