RockPaperScissors

LizardSpock

Active Record Create Unique or Return Existing Element

| Comments

When working with databases it is often a requirement to have unique elements (columns) which are not the primary key, this can be achieved in the active record model with:

require 'rubygems'
require 'sequel'
DB = Sequel.sqlite('./lesson4.db')
DB.create_table :tags do
   primary_key :id
   varchar :tag
end  

require 'rubygems'
require 'active_record'
ActiveRecord::Base.establish_connection(
  :adapter   => 'sqlite3',
  :database  => './lesson4.db'
)
class Tag <  ActiveRecord::Base
   validates_uniqueness_of :tag, :scope => :tag
end

@tag = Tag.create( :tag => "duck" )
##<Tag id: 1, tag: "duck">
@tag = Tag.create( :tag => "duck" )
##<Tag id: nil, tag: "duck">

So you can see that this constraint works nicely to stop duplicates, if it does find one it does not return the existing element, good for creating but not reusing existing elements.

I find that the following method is usually what I want:

require 'rubygems'
require 'active_record'
ActiveRecord::Base.establish_connection(
  :adapter   => 'sqlite3',
  :database  => './lesson4.db'
)
class Tag <  ActiveRecord::Base
end 

@tag = Tag.find_or_create_by_tag("lazy")
##<Tag id: 2, tag: "lazy">
@tag = Tag.find_or_create_by_tag("lazy")
##<Tag id: 2, tag: "lazy">

[Added Friday 13/08/2010] If you need to run some code between creating and saving the object there is also find_or_initialize_by_

@tag = Tag.find_or_initialize_by_tag("quack")
@tag.save

This may be useful if you have accessible or protected attributes, ‘attr_accessible’ ‘attr_protected’ which may block some properties from being initialised correctly.

I discovered this in the depths of ActiveRecord Base

Comments