I have a form that allows the user to send a message to an email, and I want to add validation to it. I do not have a model for this, only a controller. How should I do this in Rails?
I was considering doing the validation in the controller, and displaying the errors to the user using the flash object. Is there a better way of doing this?
The best approach would be to wrap up your pseudo-model in a class, and add the validations there. The Rails way states you shouldn't put model behavior on the controllers, the only validations there should be the ones that go with the request itself (authentication, authorization, etc.)
In Rails 2.3+, you can include ActiveRecord::Validations
, with the little drawback that you have to define some methods the ActiveRecord layer expects. See this post for a deeper explanation. Code below adapted from that post:
require 'active_record/validations' class Email attr_accessor :name, :email attr_accessor :errors def initialize(*args) # Create an Errors object, which is required by validations and to use some view methods. @errors = ActiveRecord::Errors.new(self) end # Required method stubs def save end def save! end def new_record? false end def update_attribute end # Mix in that validation goodness! include ActiveRecord::Validations # Validations! =) validates_presence_of :name validates_format_of :email, :with => SOME_EMAIL_REGEXP end
In Rails3, you have those sexy validations at your disposal :)
For Rails 3+, you should use ActiveModel::Validations
to add Rails-style validations to a regular Ruby object.
From the docs:
Active Model Validations
Provides a full validation framework to your objects.
A minimal implementation could be:
class Person include ActiveModel::Validations attr_accessor :first_name, :last_name validates_each :first_name, :last_name do |record, attr, value| record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z end end
Which provides you with the full standard validation stack that you know from Active Record:
person = Person.new person.valid? # => true person.invalid? # => false person.first_name = 'zoolander' person.valid? # => false person.invalid? # => true person.errors.messages # => {first_name:["starts with z."]}
Note that ActiveModel::Validations
automatically adds an errors method to your instances initialized with a new ActiveModel::Errors
object, so there is no need for you to do this manually.