Skip to content

Instantly share code, notes, and snippets.

@2called-chaos
Last active February 22, 2019 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 2called-chaos/46705324d913e4f9cc6b to your computer and use it in GitHub Desktop.
Save 2called-chaos/46705324d913e4f9cc6b to your computer and use it in GitHub Desktop.
Usernamegen ActiveRecord example model and rake task
# create_table "codenames", force: true do |t|
# t.integer "user_id"
# t.string "name"
# t.datetime "created_at"
# t.datetime "updated_at"
# end
# add_index "codenames", ["name"], name: "index_codenames_on_name", unique: true, using: :btree
# add_index "codenames", ["user_id"], name: "index_codenames_on_user_id", unique: true, using: :btree
class Codename < ActiveRecord::Base
class CodenameAllocRaceConditionError < Exception ; end
belongs_to :user, optional: true
scope :available, -> { where(user_id: nil) }
scope :allocated, -> { where.not(user_id: nil) }
validates :name, uniqueness: { case_sensitive: false }
def self.aquire(user)
# pessimistic locking to avoid race conditions
codename = nil
ActiveRecord::Base.uncached do
begin
codename = available.first
return nil unless codename
codename.with_lock do
if codename.user_id
raise CodenameAllocRaceConditionError
else
codename.update!(user: user)
end
end
codename
rescue CodenameAllocRaceConditionError
retry
end
end
user.id == codename.try(:user_id) ? codename : nil
end
def release!
update!(user_id: nil)
end
end
namespace :codenames do
desc 'Import codenames from namegen pool'
task :import => :environment do
cwas = Codename.available.count
puts "#{cwas} in pool (before)"
Usernamegen.all.each do |name|
Codename.where(name: name).first_or_create!
end
cnow = Codename.available.count
puts "#{cnow} (+#{cnow-cwas}) in pool (after)"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment