Есть ли в ActiveRecord встроенная функция upsert? Я знаю, что мог бы написать это сам, но я, очевидно, не хочу, если такая вещь уже существует.
Upsert в Rails ActiveRecord
Ответы (7)
Model.find_or_initialize
скорее всего делает то, что вы хотите. Вы можете связать его с save
или update_attributes
, если это имеет смысл.
Дополнительные сведения см. в руководствах по Rails.
find_or_initialize
и save
.
- person Barry Fruitman; 07.01.2017
В рельсах 6 есть потрясающая новая функция: они добавили upsert
и upsert_all
к ActiveRecord
.
Дополнительную информацию можно найти здесь https://edgeapi.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html#method-i-upsert_all
Я только что наткнулся на эту библиотеку: https://github.com/seamusabshere/upsert
Я еще не проверял это, но выглядит многообещающе
Механизм IMO Upsert требует индивидуальной настройки для каждой модели.
Таким образом, лучшим решением было бы реализовать собственный SQL-запрос для модели, например.
insert into <table> (<field_1>, ..., <field_n>)
values (<field_1_value>, ..., <field_n_value>)
on duplicate key update
field_x = field_x_value,
...
field_z = field_z_value;
Также есть Model.find_or_create
Rails 6 вводит create_or_find_by для этого случая https://github.com/rails/rails/pull/31989
Также для большого количества записей можно использовать https://github.com/zdennis/activerecord-import< /а>
Пример:
Book.import [book], on_duplicate_key_update: [:title]
Я написал сообщение в блоге о том, как мы можем достичь этого. Ознакомьтесь с ним здесь.
Вам нужно будет написать активное расширение записи. Это будет выглядеть примерно так.
module ActiveRecordExtension
extend ActiveSupport::Concern
def self.upsert(attributes)
begin
create(attributes)
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation => e
find_by_primary_key(attributes['primary_key']).
update(attributes)
end
end
end
ActiveRecord::Base.send(:include, ActiveRecordExtension)