rake models:find_invalid 2

Posted by John Philip Green
on Friday, January 04

We have been running an internal 'production' deployment of LearnHub.com for over a month. With the private beta starting in a couple weeks, we need to scrub the database of bad objects that accumulated during development and testing.

The most common source of this db cruft is destroying objects when we don't have the ActiveRecord associations properly set to do cascading deletes (aka :dependent=>:destroy). We are now better at writing tests for these (its easy to overlook) but that doesn't help the current state of our database.

So here's a little rake task that we whipped up to help our scrubbing:

require "db_tasks"

namespace :models do

  desc "Report any invalid ActiveRecord objects in the database."
  task :find_invalid => :environment do

    # Iterate over all constants and find just ActiveRecord models
    Object.constants.each do |c|
      klass = eval(c, TOPLEVEL_BINDING)
      if klass.is_a?(Class) && klass < ActiveRecord::Base

        invalid_object_ids = klass.find(:all).reject { |o| o.valid? }.collect { |o| o.id }
        puts "#{invalid_object_ids.size} invalid #{klass.to_s} objects: #{invalid_object_ids.join(', ')}" unless invalid_object_ids.empty?

      end
    end
  end
end

It will run through all your ActiveRecord models, and for each print out the IDs of any invalid objects.

We even found some invalid objects in our fixtures! And we run a pretty tight ship. I bet you'll find some in your project.

We will likely integrated this into a weekly routine to monitor the health of our production database. We could even run it post-deployment with Capistrano, and perhaps email the results.

Immutable Attribute Plugin 5

Posted by wesley.moxam
on Tuesday, November 13

A new Ruby on Rails validation plugin that allows you to mark model attributes as immutable.

Rails surprisingly does not include a validation method to make a model attribute immutable. (That is, the attribute can not be changed after it is set the first time.) I created this validation plugin to help that.

To install:

  script/plugin install http://svn.savvica.com/public/plugins/ensures_immutability_of

To use, drop this in your model:

  ensures_immutability_of :attribute_name

You can specify multiple immutable attributes in one line:

  ensures_immutability_of :attribute1, :attribute2

Now if something attempts to set a protected attribute, it will raise an error. For example:

class Account < ActiveRecord::Base
  ensures_immutability_of :username, :email
end

account = Account.create(:username => 'jgreen')
...
account.update(:username => 'jgreen')  # raises ActiveRecord::ImmutableAttributeError

This plugin works especially nicely with the Email Veracity Plugin. If you have an email-verification process (such as sending an activation email) then you will most likely want to mark the email attribute as immutable, and create new records for when users add other email addresses.

But this is probably most excellent for username and relationship attributes (foreign key fields). That is exactly how we are using it on Languify.

Would love to hear any ideas on how to make this better! We really appreciated all the helpful feedback on the Email Veracity Plugin.

Also I would like to thank Paul Ingles for the inspiration for this plugin.

Update:

Rather than raising a RuntimeError when an attribute is modified, now a ActiveRecord::ImmutableAttributeError is raised instead. Thanks goes to Jeffery Hardy for the suggestion.

Email Veracity Plugin 33

Posted by Carsten Nielsen
on Tuesday, November 06

Time and time again in our Rails projects we find ourselves validating email addresses for well-formedness, often in User models like this:

  validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})\Z/i

This is fine for checking the form of an email address, but we can do more to make sure that users enter correct addresses. Anyone who's run a production site has witnessed mistyped addresses like heycarsten@gmaol.com, and with the above scheme this would be accepted. Here's where the validates_email_veracity_of plugin comes in.

  validates_email_veracity_of :email

Now in addition to checking the format, the email domain is checked for MX records. (It's remarkable how many errors this catches on our production site Languify.)

To speed things up, the plugin includes a list of popular domains which are skipped.

Just want to check the format?

  validates_email_veracity_of :email, :domain_check => false

Require a custom error message?

  validates_email_veracity_of :email, :message => 'is not correct at all.'

By default the plugin waits for two seconds before quietly skipping the domain lookup, if you want to change this timeout interval simply:

  validates_email_veracity_of :email, :timeout => 1 # => Time in seconds.

There are many other options, all documented in the README.

Install the plugin into your Rails project the standard way:

  > script/plugin install http://svn.savvica.com/public/plugins/validates_email_veracity_of

Let us know if validates_email_veracity_of has helped you, or of any improvements that come to mind. As always, patches and enhancements are encouraged.