Archive for the 'Rails Plugins' Category

01
Jan

Why you should always validate maximum lengths in models, and how to do so easily

Developers seem to rarely use validates_lengths_of with their models, despite there being an inherent maximum length on every string and text field – the one enforced by the database. Since table migrations in Rails set a fairly high maximum length for string attributes, most people don’t think twice about the possibly of that limit being exhausted. Even beyond this, there may be other reasons why the field limit is set fairly low, or perhaps you’re working with a legacy database.

Without validating maximum field lengths at the model level, ActiveRecord will still ship off the full field value as entered in an INSERT query. From there two things might happen, and this depends on the database itself.
1. It might fail the query with an ActiveRecord::StatementInvalid exception. Since this is an exception most developers don’t routinely handle, this could cause the entire request to fail. This occurs with SQL Server for sure, and possibly other databases.
2. It might accept the query and simply truncate the result to the field limit. This might sound better than #1, but IMO it’s actually worse: now you have an instance where the everything appeared to go along fine, but you might end up with missing data. This is the default behavior with MySQL.

There’s another reason why you should always validate field lengths, and that’s to limit the possibilities for a Denial of Service attack. If an attacker knows you aren’t validating field length and that whatever they’re providing is going straight into an SQL query and being sent to the database, they can craft extremely large requests that might fill up the pipe to the database. Even if the data doesn’t actually end up being inserted in full, they’ve tied up a database connection and – since the regular old “mysql” gem will block for the query result – a Rails process.

Unfortunately in order to do this properly you essentially have to write validates_length_of lines (or the equivalent ActiveRecord 3 form) for each attribute, with it’s maximum database length. To make this easy, I wrote a gem called validates_lengths_from_database that will introspect your database string field maximum lengths and automatically defines length validations for you.

To install, just include the gem in your Gemfile (works with Rails 2.3 and Rails 3.0):

gem "validates_lengths_from_database"

Then in your model you can activate validations:

  class Post < ActiveRecord::Base
    validates_lengths_from_database
  end

It also supports filter-style :only and :except options:

  class Post < ActiveRecord::Base
    validates_lengths_from_database :only => [:title, :contents]
  end

  class Post < ActiveRecord::Base
    validates_lengths_from_database :except => [:other_field]
  end

Note that this cannot be done at a global level directly against ActiveRecord::Base, since the validates_length_from_database method requires the class to have a table name (with the ability to load the schema).

For more information or to view the source, check out the project on GitHub: validates_lengths_from_database

30
Dec

ActiveRecord Drafts with has_draft

I ran into a problem a while back of creating draft copies of ActiveRecord models for the purpose of establishing a draft/live system. I’ve since found a reason to resurrect this and publish it to GitHub and clean some things up. Check out has_draft on GitHub.

has_draft allows for multiple “drafts” of a model which can be useful when developing:

  • Draft/Live Version of Pages, for examples
  • A workflow system whereby a live copy may need to be active while a draft copy is awaiting approval.

The semantics of this as well as most of the inspiration comes from version_fu, an excellent plugin for a similar purpose of maintaining several “versions” of a model.

This was built to be able to be tacked on to existing models, so the data schema doesn’t need to change at all for the model this is applied to. As such, drafts are actually stored in a nearly-identical table and there is a has_one relationship to this. This separation allows the base model to really be treated just as before without having to apply conditions in queries to make sure you are really getting the “live” (non-draft) copy: Page.all will still only return the non-draft pages. This separate table is backed by a model created on the fly as a constant on the original model class. For example if a Page has_draft, a Page::Draft class will exist as the model for the page_drafts table.

Basic Example::

## First Migration (If Creating base model and drafts at the same time):
class InitialSchema < ActiveRecord::Migration

  [:articles, :article_drafts].each do |table_name|
    create_table table_name, :force => true do |t|
      t.references :article if table_name == :article_drafts

      t.string :title
      t.text :summary
      t.text :body
      t.date :post_date
    end
  end
end

## Model Class
class Article < ActiveRecord::Base
  has_draft
end

## Exposed Class Methods & Scopes:
Article.draft_class
=> Article::Draft
Article.with_draft.all
=> (Articles that have an associated draft)
Article.without_draft.all
=> (Articles with no associated draft)

## Usage Examples:
article = Article.create(
  :title => "My Title",
  :summary => "Information here.",
  :body => "Full body",
  :post_date => Date.today
)

article.has_draft?
=> false

article.instantiate_draft!

article.has_draft?
=> true

article.draft
=> Article::Draft Instance

article.draft.update_attributes(
  :title => "New Title"
)

article.replace_with_draft!

article.title
=> "New Title"

article.destroy_draft!

article.has_draft?
=> false

Custom Options::

## First Migration (If Creating base model and drafts at the same time):
class InitialSchema < ActiveRecord::Migration

  [:articles, :article_copies].each do |table_name|
    create_table table_name, :force => true do |t|
      t.integer :news_article_id if table_name == :article_copies

      t.string :title
      t.text :summary
      t.text :body
      t.date :post_date
    end
  end

end

## Model Class
class Article < ActiveRecord::Base
  has_draft :class_name => 'Copy', :foreign_key => :news_article_id, :table_name => 'article_copies'
end

Method Callbacks:
There are three callbacks you can specify directly as methods.

class Article < ActiveRecord::Base
  has_draft

  def before_instantiate_draft
    # Do Something
  end

  def before_replace_with_draft
    # Do Something
  end

  def before_destroy_draft
    # Do Something
  end
end

Block of Code Run for Draft Class:
Because you don’t directly define the draft class, you can specify a block of code to be run in its
context by passing a block to has_draft.

class Article < ActiveRecord::Base
  belongs_to :user

  has_draft do
    belongs_to :last_updated_user

    def approve!
      self.approved_at = Time.now
      self.save
    end
  end

end
26
Nov

message_block: a error_messages_for replacement for flash message and model error handling

Message Block Example

One of the most common needs in any application I build is to have some abstract way of handling messages to end users.  Sometimes I’ll want to show a confirmation message or a warning.  Other times I’ll want to show a confirmation message but also show ActiveRecord validations.  While the error_messages_for helper in Rails works fairly well for showing ActiveRecord validation issues, I wanted a unified approach to handling this and flash messaging with multiple flash types in one package.

I blogged before about an approach I developed to solve this problem, I rolled my own message_block plugin.  The README file explains things pretty so be sure to check it out for more details, but here is the intro:

Introduction:

Implements the common view pattern by which a list of messages are shown at the top, often a combination of flash messages and ActiveRecord validation issues on one or more models. This allows for a nice, stylized block of messages at the top of the page with icons indicating what type of message it is (error, confirmation, warning, etc.)

This view helper acts as a replacement for error_messages_for by taking error messages from your models and combing them with flash messages (multiple types such as error, confirm, etc.) and outputting them to your view. This plugin comes with an example stylesheet and images.

Usage:

Once you install this, you should now have a set of images at public/images/message_block and a basic stylesheet installed at public/stylesheets/message_block.css. First you’ll want to either reference this in your layout or copy the declarations to your main layout. Then you can use the helper <%= message_block %> as described below:

The first argument specifies a hash options:

  • :on – specifies one or many model names for which to check error messages.
  • :model_error_type – specifies the message type to use for validation errors; defaults to ‘error’
  • :flash_types – specifies the keys to check in the flash hash. Messages will be grouped in ul lists according to this type. Defaults to: %w(back confirm error info warn)
  • :html – Specifies HTML options for the containing div
  • :id – Specifies ID of the containing div; defaults to ‘message_block’
  • :class – Specifies class name of the containing div; defaults to nothing.

Imagine you have a form for entering a user and a comment:

<%= message_block :on => [:user, :comment] %>

Imagine also you set these flash variables in the controller:

  class CommentsController
    def create
      flash.now[:error] = "Error A"
      flash.now[:confirm] = "Confirmation A"  # Note you can use different types
      flash.now[:warn] = ["Warn A", "Warn B"]  # Can set to an array for multiple messages
    end
  end

And let’s say that you want to show these messages but also show the validation issues given that both user and comment fail ActiveRecord validation:

  <div id="message_block">
    <ul class="error">
      <li>Error A</li>
      <li>User first name is required.</li>
      <li>Comment contents is required.</li>
    </ul>
    <ul class="confirm">
      <li>Confirmation A</li>
    </ul>
    <ul class="warn">
      <li>Warn A</li>
      <li>Warn B</li>
    </ul>
  </div>

Which will by default leave you with this look:

Message Block Example

message_block on GitHub

20
Dec

Nested URL Parameters

One of the great things about Rails is the ability to wire together form logic with extreme ease through Rails’ support of essentially representing hashes through the “object[name]” syntax of URL parameters. Arrays are also supported in a similar manner, making things like many-to-many relationship management cake.

In Rails 1.2 one issue I ran into is that this hash-based access logic cannot be nested when using helpers such as url_for (which is in turned used by helpers such as link_to, etc.) This type of functionality is rather useful when you are trying to encapsulate a set of name-value pairs within one “thing”, such as a “search” which is many criteria => value pairs. For a particularly project of mine I established a pretty nice design pattern for working with searches and results in a very abstract manner, an area of Rails that I generally find underdeveloped with no standard practice.

I was lucky to stumble on a Rails plugin that monkey-patches Rails to support this: nested_params_patch. Information about this plugin is quite sparse but this article does a good job of better-explaining what the plugin does. Essentially it allows you to do things like this:

person_url(:name => {0 => 'Ryan', 1 => 'Kinderman})

Pretty cool stuff! I am always amazed and the kind of plugins and extensions that are possible, all resulting from Ruby’s dynamicism and Rails’ heavily extensible architecture.