Michael Anhari

Ensuring a column is unique for an entity in Rails

Four avocado halves on a board, three showing the skin and one showing the stone

In a previous article, we talked about guaranteeing unique values for a database column in Rails. Today let's expand upon that and see how we can do the same, but not across the entire table.

For example, let's say we have a table of Articles that belong to a User:

class Article < ApplicationRecord
  belongs_to :user
end

class User < ApplicationRecord
  has_many :articles
end

and that we want to guarantee that each article for a given user has a unique title. In other words, Bob and Sally can both write articles titled "How to Adopt a Retired Racing Greyhound" but neither of them can write two articles with that title.

Validating at the ORM level with ActiveRecord

Validating this in our Rails model is pretty straight forward.

class Article < ApplicationRecord
  belongs_to :user

  validates :title, uniqueness: { scope: :user_id }
end

This scopes our uniqueness validation to values that are unique for the record's user_id.

Ensuring uniqueness at the database level

Adding database-level protections for this feature involves creating a unique index that is based on multiple columns (title and user_id):

class AddUniqueIndexForArticleTitlesAndUserIds < ActiveRecord::Migration[6.0]
   def change
     add_index :articles, [:title, :user_id], unique: true
   end
 end

And there you have it! Your records will be properly validated, and uniquely scoped to each user.

Newsletter

I'm working on sending out a weekly newsletter. I'll make it as easy as possible to unsubscribe at any time.