Active Model in Rails

The technique we used was quite a hack as this is something that ActiveRecord wasn’t designed to do but now in Rails 3.0 we have a new feature called ActiveModel which makes doing something like this a lot easier.

Active Model in Rails

Before we get into the details of ActiveModel we’ll first describe the part of the application that we’re going to modify to use it.

Active Model in Rails 3.0

The screenshot above shows a contact form that has been created using Rails’ scaffolding. The application has a model called Message that is currently backed by ActiveRecord which means that we’re managing messages through the database. We’re going to change the way this form works so that it just sends emails and doesn’t store messages in a database table.

When you’re thinking of doing something like this it’s always a good idea to first consider your requirements and make sure that you really don’t want to store the data from the form in a database as there are often good side-effects to doing this. A database can act as a backup and also makes it easier to move the message-sending into a queue in a background process. For the purposes of this example, however, we don’t want any of that functionality so we’re free to go ahead and make our model tableless.

Message inherits from ActiveRecord::Base as you would expect a model class to, but as we don’t want this model to have a database back-end we’re going to remove that inheritance. As soon as we do this, though, our form will no longer work as the validators are provided by ActiveRecord. Fortunately, we can restore this functionality by using ActiveModel.

If we take a look at the Rails 3 source code we’ll see the that there are activerecord and activemodel directories. The core Rails team has taken everything from ActiveRecord that wasn’t specific to the database backend and moved it out into ActiveModel. ActiveRecord still relies heavily on ActiveModel for the functionality that isn’t specific to the database and as ActiveModel is full-featured and thoroughly tested it’s great for use outside ActiveRecord.

It we take a look in the directory that contains the code for ActiveModel we can see the functionality that it provides.

We can see from the list above that ActiveModel includes code to handle callbacks, dirty tracking, serialization and validation, among other things. The last of these is exactly what we’re looking for.

The code for validations has the following comment near the top and we can see from it that it’s fairly easy to add validations to a model. All we need to do is include the Validations module and provide getter methods for the attributes that we’re calling validators on.

Message inherits from ActiveRecord::Base as you would expect a model class to, but as we don’t want this model to have a database back-end we’re going to remove that inheritance. As soon as we do this, though, our form will no longer work as the validators are provided by ActiveRecord. Fortunately, we can restore this functionality by using ActiveModel.

If we take a look at the Rails 3 source code we’ll see the that there are activerecord and activemodel directories. The core Rails team has taken everything from ActiveRecord that wasn’t specific to the database backend and moved it out into ActiveModel. ActiveRecord still relies heavily on ActiveModel for the functionality that isn’t specific to the database and as ActiveModel is full-featured and thoroughly tested it’s great for use outside ActiveRecord.

It we take a look in the directory that contains the code for ActiveModel we can see the functionality that it provides.

We can see from the list above that ActiveModel includes code to handle callbacks, dirty tracking, serialization and validation, among other things. The last of these is exactly what we’re looking for.

The code for validations has the following comment near the top and we can see from it that it’s fairly easy to add validations to a model. All we need to do is include the Validations module and provide getter methods for the attributes that we’re calling validators on.

This isn’t enough to get our model to behave as the controller expects it to, though. There are two problems in the create method. Firstly the call to Message.new won’t work as our Message model no longer has an initializer that takes a hash of attributes as an argument. Secondly, save won’t work as we don’t have a database backend to save the new message to.

We can solve the first problem by writing an initialize method in the Message model that takes a hash as a parameter. This method will loop through each item in the hash and assign the value to the appropriate attribute for the message using the send method.

If we reload the form now we’ll see that we’re not quite there yet, however.

This time the error is caused by a missing to_key method in the Message model. The error is thrown by the form_for method so it seems that Rails itself is expecting our model to have functionality that it doesn’t yet support. Let’s add that functionality now.

Rather than guessing everything that Rails expects the model to have there’s a nice lint test included with ActiveModel that allows us to check whether our custom model behaves as Rails expects it to. If we include the ActiveModel::Lint::Tests module in a tests for the model it will check that the model has all of the required functionality.

The source code for the Lint::Tests module shows the methods that the model needs to respond to in order for it to work as it should, including to_key. We can make our model work by including a couple of ActiveRecord modules. The first of these is Conversion, which provides that to_key method and several others. The other module is the Naming module, but in this case we extend it in our class rather than including it as it includes some class methods.

As well as including the Conversion module we need to define a persisted? method in our model, which needs to return false as our model isn’t persisted to a database. With these changes in place our Message model now looks like this:

If we reload the form now it will work again which means that the Message model now satisfies all of the requirements that Rails 3 relies on for a model. If we try to submit the form we’ll see that the validators are working, too.

We’ve only covered a little of what ActiveModel provides in this episode but this should have been enough to whet your appetite and give you a reason to look more deeply into its source code to see what it can do. The code is well documented and structured so if you see something you might find useful then there should be enough information in the comments for that file to get you started using it.

About The Author

Purab

My name is Purab Kharat, Here is my Personal Blog: wpapi.com. Work as an Senior Technical Lead at Smartsourcing Global Pvt Ltd in Princeton, NJ, USA. I contributor of many wordpress plugins and Drupal Modules. I am core developer of Drupal. Connect to on LinkedIn or Follow @purab on Twitter or Follow me on Google+ or Write Mail to purabdk@gmail.com or Chat with me on Skype : purabdk