Is Unique

This is a simple ActiveRecord extension that makes sure that no duplicate records are added to the database. When you create a new model instance that already exists, it won’t create a new record, but will return the existing one instead. The extension generates a hash off the model attributes and use it to check for existing records. Of course, it ignores primary key, created_at, updated_at and other columns that you ask it to.

Here’s an example. Say you have a Location model and you want all your locations to be unique. When you add a new location you’d like to check whether it already exists and if it does, you don’t want to create a new record.

$ ./script/generate model Location name:string lat:float lng:float alias:string

IsUnique will take care of that. You need to install the gem:

$ sudo gem install is_unique

Then you need to add a column to your table to store a unique hash that would be used to check for existing records. The gem includes a generator for that:

$ ./script/generate is_unique Location

In the model you need to specify that it’s supposed to be unique:

class Location < ActiveRecord::Base

is_unique

end

Then fire up the console and try it:

>> l = Location.create(:name => ‘London’, :lat => ‘51.5’, :lng => ‘-0.13’, :alias => ‘Londinium’)

Location Load (0.4ms)   SELECT * FROM `locations` WHERE (`locations`.`unique_hash` = '...') LIMIT 1
Location Create (0.6ms)   INSERT INTO "locations" ...

> #<Location id: …>

>> l.clone.save

Location Load (0.7ms)   SELECT * FROM "locations" WHERE ("locations"."unique_hash" = '...') LIMIT 1
Location Load (0.6ms)   SELECT * FROM "locations" WHERE ("locations"."id" = 1)

> true

Now there’s a couple of customization options. First, you can ignore certain attributes when calculating the hash. Say there may be different aliases for a location, but you still want just one record in the database. The is_unique method accepts an ignore parameter for that purpose:

class Location < ActiveRecord::Base

is_unique :ignore => :alias

end

>> l = Location.last

Location Load (0.7ms)   SELECT * FROM "locations" ORDER BY locations.id DESC LIMIT 1

> #<Location …>

>> n = l.clone

> #<Location …>

>> n.alias = ‘Something different’

> “Something different”

>> n.save

Location Load (0.7ms)   SELECT * FROM "locations" WHERE ("locations"."unique_hash" = '...') LIMIT 1
Location Load (0.6ms)   SELECT * FROM "locations" WHERE ("locations"."id" = 2)

> true

>> n == l

> true

If you’d like to name the unique hash column differently (it’s “unique_hash” by default), you need to provide the name to the generator:

$ ./script/generate is_unique Location my_unique_hash_column_name

and specify it in the model:

class Location < ActiveRecord::Base

is_unique :hash_column => :my_unique_has_column_name

end

Copyright © 2010 Loco2, released under the MIT license