Validating Data with ActiveRecord

Problem

You want to prevent bad data from getting into your ActiveRecord data objects, whether the source of the data is clueless users or buggy code.

Solution

The simplest way is to use the methods defined by the ActiveRecord::Validations module. Each of these methods (validates_length_of, validates_presence_of, and so on) performs one kind of validation. You can use them to declare restrictions on the data in your objects fields.

Lets add some validation code to the Comment class for the weblog application first seen in Recipe 13.11. Recall that a Comment object has two main fields: the name of the author, and the text of the comment. Well reject any comment that leaves either field blank. Well also reject comments that are too long, and comments whose body contains any string from a customizable list of profane words.

	require cookbook_dbconnect
	activerecord_connect
	
	class Comment < ActiveRecord::Base
	 @@profanity = %w{trot krip}
	 @@no_profanity_re = Regexp.new(^(?!.*( + @@profanity.join(|) + )))

	 validates_presence_of %w{author}
	 validates_length_of :content, :in => 1..200
	 validates_format_of :content, :with => @@no_profanity_re,
	 :message => contains profanity
	end

Comment objects that don fit these criteria won be saved to the database.

	comment = Comment.create
	comment.errors.on author # => "can	 be blank"
	comment.errors[content]
	# => "is too short (minimum is 1 characters)"
	comment.save # => false

	comment = Comment.create(:content => x * 1000)
	comment.errors[content]
	# => "is too long (maximum is 200 characters)"

	comment = Comment.create(:author => Alice,
	 :content => "About what Id expect from a trotting krip such as yourself!")
	comment.errors.count # => 1
	comment.errors.each_full { |msg| puts msg }
	# Content contains profanity

	comment = Comment.create(:author => Alice, :content => I disagree!)
	comment.save # => true

Discussion

Every ActiveRecord record has an associated ActiveRecord::Errors object, which starts out empty. Before the record is saved to the database, all the predefined restrictions for that class of object are checked. Every problem encountered while applying the restrictions adds an entry to the Errors object.

If, at the end of this trial by ordeal, the Errors object is still empty, ActiveRecord presumes the data is valid, and saves the object to the database.

ActiveRecords Validations module provides many methods that implement validation rules. Apart from the examples given above, the validates_numericality_of method requires an integer value (or a floating-point value if you specify :integer => false). The requires_inclusion_of method will reject any value not found in a predefined list of acceptable values.

If the predefined validation rules aren enough for you, you can also write a custom validation rule using validate_each. For instance, you might validate URL fields by fetching the URLs and making sure they e valid.

The method Errors#each_full prepends each error message with the corresponding field name. This is why the actual error messages look like "is empty" and "contains profanity": so each_full will yield "Author is empty" and "Content contains profanity".

ActiveRecord assumes you named your fields so that these messages will be readable. You can customize the messages by passing in keyword arguments like :message, but then youll need to access the messages with Errors#each instead of Errors#each_full. Heres an alternate implementation of the Comment validation rules that customizes the messages:

	require cookbook_dbconnect
	activerecord_connect

	class Comment < ActiveRecord::Base
	 @@profanity = %w{trot krip}
	 @@no_profanity_re = Regexp.new(^(?!.*( + @@profanity.join(|) + )))

	 validates_presence_of %w{author}, :message => Please enter your name.
	 validates_length_of :content, :in => 1..200,
	 :too_short => Please enter a comment.,
	 :too_long => Comments are limited to 200 characters.
	 validates_format_of :content, :with => @@no_profanity_re,
	 :message => Try to express yourself without profanity.
	end

The declarative validation style should be flexible enough for you, but you can do custom validation by defining a validate method. Your implementation is responsible for checking the current state of an object, and populating the Errors object with any appropriate error messages.

Sometimes new objects have different validation rules from existing objects. You can selectively apply a validation rule by passing it the :on option. Pass in :on => :create, and the validation rule will only be triggered the first time an object is saved to the database. Pass in :on => :update, and the validation rule will be triggered every time except the first. You can also define the custom validation methods validate_on_add and validate_on_update as well as just plain validate.

See Also

  • Recipe 1.19, "Validating an Email Address"
  • Recipe 8.6, "Validating and Modifying Attribute Values"
  • The built-in validation methods (http://rubyonrails.org/api/classes/ActiveRecord/Validations/ClassMethods.html)
  • Some sample validate implementations (http://rubyonrails.org/api/classes/ActiveRecord/Validations.html)
  • The Errors class defines a few helper methods for doing validation in a validate implementation (http://rubyonrails.org/api/classes/ActiveRecord/Errors.html)
  • Og defines some declarative validation methods, similar to ActiveRecords (http://www.nitrohq.com/view/Validation/Og)


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net