Category Archives: Rails

Post navigation

With Rails’s ActiveRecord and presumably other object-relational mappers, it is easy to use persistent, database-backed objects as if they were just there. Create new objects, navigate along associations, just like that. This picture breaks down however, when it comes time to ensure those in-memory changes are saved back to the database.

In general, in a single unit of work, we only want to read an object once from the database and write changes to that object, if any, back to the database at most once.

The “reading once” part is mostly handled by an identity map. Such a map does not prevent multiple reads of the same object through conditional queries, but it does ensure that each persistent object has a single in-memory representation and it does avoid reading the same object twice when the object is accessed by its id (primary key).

The writing part is harder, because a changed or new object might not be valid by the constraints imposed by the application or the database. In effect, writing/saving must be done explicitly in order to react to the possible error conditions. In a lot of common cases this fits in nicely with the business logic.

Say your application provides the functionality to send a message. It is part of your business logic to check that the user has indeed entered a valid message, one having some text for the body. So when you write code like this

Note that each method by itself ensures that changes are written to the database. As a result, we can compose these methods easily without any further concern that the changes they effect have to be written explicitly to the database.

Unfortunately, there is a drawback. The price we pay is that the same object is written to the database twice because each change is saved individually.

How about not saving the message in mark_as_read and register_last_reader and instead doing it in the controller action?

This works, needs only a single database write -- and results in less compositional, more risky code because now mark_as_read and register_last_reader implicitly shift responsibility to their calling context.

Now to the denouement. I don't have a handy solution that satisfies all constraints, but I do have a code snippet that helps make the second approach less risky.

This version is for Mongoid, but the idea is applicable to other ORMs that use an identity map. And importantly, the identity map must be enabled for this to work.

What It Does and Why

The after_filter logs and raises an exception if the identity map contains any objects that should have been saved. In particular, these are the objects that have changes to their attributes, excluding non-essential technical attributes, and where no failed attempt has been made to save them explicitly. We don't care for objects with errors, because we assume that such an object is explicitly handled. We do care about the forgotten objects, changed but never saved.

You’re using git to manage your Ruby on Rails projects? Then you’ve probably come to appreciate topic branches as a kind of transaction facility for programmers. If you need to implement a non-trivial or just try something, the way to go is onto a new “topic” branch. There you can mangle the code all you like, without fearing to cause any lasting harm. In case everything works out fine, you merge the branch into the master branch and discard it. If you come to a dead end — well, you just discard the misbegotten branch.

But what about the database? If moving along your branch involves changes to the database, structural changes in particular, you can’t easily switch to another branch without these changes. In other words, your development database is really only suitable for a single branch.

Up to now, that is. Install the branch_db gem and what you get is a private database for your branch that you can mutilate without interfering with work on the other branches.

For details and installation instructions see the README. Here’s just an appetizer. Say you’re on branch “feature” and want a private copy of the “master” database. Here’s how you do it:

Didn’t you always want to write your Rails views as plain Ruby objects? — “What?”, I hear you say. No, I haven’t lost my mind and the idea is quite sensible (or so I hope), once you add the restriction that it is JSON-formatted data that you want to return.

Say you need to set up some hashes or arrays for rendering to JSON. This is best done in Ruby and it is clearly a view concern. So let’s do it in the views. Like this:

Invariably, in almost every application there happen to be lists of data items that are immutable, just for reference. It could be colors, the four seasons, continents, the states of your country, kinds or types of this and that. These items are almost like constants. As accessible as they are through the ordinary ActiveRecord API, it seems an utter waste to hit the database again and again, for data that won’t change however often you request it.

Of course, the Rails community recognized early on that some data are more constant than others and over the years several plugins have been published that add cached and easily accessible enumerations to ActiveRecord. Some of these additions are quite complicated or befuddle ActiveRecord by not backing the enumeration values with real database objects. My experience has been that these attempted optimizations result in bizarre behavior when I did interesting things with ActiveRecord such as multiply nested named scopes plus custom SQL.

So, I thought a basic, no, simplistic, version of enumerations is called for. Here’s how it looks:

ensures that a Color object with name ‘red’ exists, if it does not, one is created.

Caveats

Although there is a #reload method defined on enumeration models, i.e. Color.reload, it is very unwise to use it. The point is that this method only affects a single server process and you most likely have many of them.

So, if you need to change enumeration values, the only way to do it is to treat it like an update to your application code.

Let your Rails app know about it

On a Rails project I’m currently working on I need to fill the database with test data to have something to play with. Apart from large imports, that’s the time when indexes may slow down operation severely instead of speeding things up. Consider: The indexes are not used, but have to be updated again and again for each new record that is inserted into the database. It is much cheaper, to lift — well, really drop — the indexes during mass operation and recreate them afterwards.

Please bear in mind that dropping and creating of indexes is a rather intrusive operation on the structure of your database. You should only perform it while no other users (or processes) are accessing it.

Also, consider that some indexes may be important for the proper function of your database. If you have unique indexes, i.e. indexes that enforce that particular columns or combinations of columns are unique, and if you are handling violations of this constraint in your application code, then you might need to retain these indexes even during data generation.

Let your Rails app know about it

The Rails generator script/generate knows pretty well what things it can generate. In fact, it knows much better than I do. So, I think it could really give me some help when I’m typing along on the command line.

If you save the snippet below as /etc/bash_completion.d/generate you can enjoy this help, too.

I’m not yet so enlightened that all of my Rails unit and functional tests run without accessing the database. Indeed, I’m still using YAML fixtures to populate the database for testing.

I also insist on having foreign key constraints in the database, a thing that’s not exactly encouraged by Rails, but which is quite possible nonetheless. The various plugins from RedHill Consulting are a big help.

But then, when you feel all warm and cosy due to the additional safety at the database-level, you’re suddenly trapped by a snag: Sooner or later you find that your fixtures contain dependencies among objects that preclude any attempt at clever ordering by violating one foreign key constraint or another. Fixture files are loaded one after another in their entirety and when an object in an earlier fixture refers to an object in a later fixture, the database aptly notices as an inconsistency.

Well, you may think, it is an inconsistency, but only a temporal one. After all the fixture files are loaded, everything is consistent again. That’s the clue. We need to tell the database that, yes, indeed, things may be inconsistent for a time, but we’ll be cleaning up, promise. The good thing is that there is even an SQL standard-compliant way to express this promise.

START TRANSACTION
SET CONSTRAINTS ALL DEFERRED
COMMIT

If you use transactional fixtures, the transaction bracket is already provided by Rails, but there’s no pretty way to sneak in the "SET CONSTRAINTS ..." line. There are two ways of slightly different brutality. First, you can edit activerecord/lib/fixtures.rb and just insert the required line.

Note that with transactional fixtures this results in each fixture file loaded only once for all the tests.

So, there we are a last. Or those with a reasonable DBMS, I might say. For, of course, this technique is no use, if your database does not support deferrable constraints. PostgreSQL for one does support them.

I’ve recently started to add XML support to a Rails application, meaning that the application provides data in XML format, if the request asks for it, and it understands XML data on create or update.

To keep the application as well as myself sane, I’ve written a test that ensures the round trip of getting XML and updating an object by sending XML works. This is only a very basic test and there surely is more that can and should be tested.