Sha256: 6e0f923210c843d3e0703291c10b1618a47722faa1914ef4a705ea895e95284a

Contents?: true

Size: 1.62 KB

Versions: 8

Compression:

Stored size: 1.62 KB

Contents

require 'active_record'
require 'pg'

module Dino
  # Provides a simple way to do an create or update of an ActiveRecord object.
  module Upsert
    extend ActiveSupport::Concern
    # User.upsert
    module ClassMethods
      def upsert(*args, &block)
        Dino::Upsert.upsert(self, *args, &block)
      end
    end

    # klass: The ActiveRecord class we are upserting against.
    # conditions: what should match the upsert
    # options: what we are updating/inserting
    # If provided, the block gets the object before it's saved, in case
    #   there's special init options necessary for it.
    # rubocop:disable MethodLength
    def self.upsert(klass, data, options = {}, &block)
      retry_count = 0
      data_copy = {}
      data ||= []
      data.each do |k, v|
        v = klass.column_for_attribute(k).type_cast_for_database(v) if v.is_a?(Hash)
        data_copy[k] = v
      end
      begin
        klass.transaction(requires_new: true) do
          object = klass.where(data_copy).first_or_initialize
          block.call(object) if block
          object.tap do |t|
            t.assign_attributes(options)
            t.save! if t.changed?
          end
        end
      rescue PG::UniqueViolation, ActiveRecord::RecordNotUnique
        # If there's a unique violation, retry this. But only a certain amount
        # of times or we'll get into an infinite loop if something's messed up.
        # (like an incorrect unique index or something)
        if retry_count < 10
          retry_count += 1
          retry
        else
          raise
        end
      end
    end
  end
end

ActiveRecord::Base.send(:include, Dino::Upsert)

Version data entries

8 entries across 8 versions & 1 rubygems

Version Path
dino_utils-0.1.21 lib/dino/upsert.rb
dino_utils-0.1.20 lib/dino/upsert.rb
dino_utils-0.1.19 lib/dino/upsert.rb
dino_utils-0.1.18 lib/dino/upsert.rb
dino_utils-0.1.16 lib/dino/upsert.rb
dino_utils-0.1.15 lib/dino/upsert.rb
dino_utils-0.1.14 lib/dino/upsert.rb
dino_utils-0.1.13 lib/dino/upsert.rb