Skip to content

Instantly share code, notes, and snippets.

@marcelorxaviers
Last active November 28, 2018 16:03
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 marcelorxaviers/9fc7ffeec007e497477cfc412de285bc to your computer and use it in GitHub Desktop.
Save marcelorxaviers/9fc7ffeec007e497477cfc412de285bc to your computer and use it in GitHub Desktop.
class BatchCreate
class << self
def perform(active_records:, conflict_fields:)
return if active_records.empty?
ActiveRecord::Base.connection.execute(
<<-SQL.squish
#{insert_statement(active_records.first)}
#{values(active_records)}
#{on_conflict_statement(conflict_fields)}
SQL
)
end
private
INSERT_REGEX = /(INSERT INTO .* VALUES) (.*)/
def insert_statement(active_record)
sql = active_record.class.arel_table.create_insert.tap do |insert_manager|
insert_manager.insert(
active_record.send(:arel_attributes_with_values_for_create, active_record.attribute_names.sort)
)
end.to_sql
INSERT_REGEX.match(sql).captures[0]
end
def on_conflict_statement(conflict_fields)
return ';' if conflict_fields.blank?
"ON CONFLICT (#{conflict_fields.join(', ')}) DO NOTHING"
end
def values_for(active_record)
active_record.updated_at = Time.now if active_record.respond_to?(:updated_at)
active_record.created_at ||= Time.now if active_record.respond_to?(:created_at)
sql = active_record.class.arel_table.create_insert.tap do |insert_manager|
insert_manager.insert(
active_record.send(:arel_attributes_with_values_for_create, active_record.attribute_names.sort)
)
end.to_sql
INSERT_REGEX.match(sql).captures[1]
end
def values(active_records)
active_records.map { |active_record| values_for(active_record) }.join(",")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment