Question: How do I use "UPSERT" or "INSERT INTO likes (user\_id,person\_id) VALUES (32,64) ON CONFLICT (user\_id,person\_id) DO NOTHING" in PostgreSQL 9.5 on Rails 4.2?

Answer: 
Have a look at `active_record_upsert` gem here: <https://github.com/jesjos/active_record_upsert>. This does the upsert, but obviously only on Postgres 9.5+.
You can achieve that by creating the SQL using the active records internals. You can use the `arel_attributes_with_values_for_create` to extract values for each active\_record for the insert sql with the Rails attributes, something like:

```
INSERT_REGEX = /(INSERT INTO .* VALUES) (.*)/

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

```

Then you can add all the values into one big "values" string:

```
def values(active_records)
  active_records.map { |active_record| values_for(active_record) }.join(",")
end

```

For the insert part of the SQL you can use a similar code to the one used for the value extraction:

```
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

```

For the conflict part you can do the following:

```
def on_conflict_statement(conflict_fields)
  return ';' if conflict_fields.blank?

  "ON CONFLICT (#{conflict_fields.join(', ')}) DO NOTHING"
end

```

At the end just concatenate all of them together for execution:

```
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

```

You can check [here](https://gist.github.com/marcelorxaviers/9fc7ffeec007e497477cfc412de285bc) the final solution.

This is the output for me - using my **balance** active record model and removing the piece of code that executes the SQL(`ActiveRecord::Base.connection.execute...`):

```
> puts BatchCreate.perform(active_records: [balance], conflict_fields: [:bank_account_id, :date])
INSERT INTO "balances" ("amount", "created_at", "currency", "date", "id", "bank_account_id", "updated_at") VALUES (0, '2018-11-28 15:42:44.312954', 'MXN', '2018-11-28', 15169, 26300, '2018-11-28 16:05:07.465402') ON CONFLICT (bank_account_id, date) DO NOTHING 

```