Возможно, есть лучший способ сделать это, но это лучшее из того, что я могу придумать на данный момент.
В ассоциации has_many (: through) accepts_nested_arguments_for использует присвоение виртуальному атрибуту #{association}_attributes
, чтобы применить магию. Он ожидает массив хэшей, где каждый хеш содержит ключи атрибутов и их значения. Любые хэши с идентификатором будут обновлены (или удалены, если есть ключ :_delete
со значением true). Любые хэши, в которых отсутствует идентификатор, будут использоваться для создания новых элементов этой ассоциации. Таким образом, ключ заключается в том, чтобы перехватить вызов tags_associations=
и проверить все хэши, в которых отсутствуют идентификаторы для существующего тега с тем же значением имени, и заменить его записью, которую tags_attributes будет использовать для установления связи с существующим тегом , N.B. для отношений has_one и own_to tag_attributes ожидает один хеш. Код будет похож, но намного проще.
class Thing < ActiveRecord::Base
has_many :tags, :through => :taggings
has_many :taggings
accepts_nested_attributes_for :tags
def tags_attributes_with_recycling=(attributes)
existing_attributes = attributes.reject{|attribute| attribute[:id].nil?}
new_attributes = attributes - existing_attributes
new_and_recycled_attributes = new_attributes.map { |attribute|
tag_id = Tag.find_by_name(attribute[:name]).id
tag_id ? {:id => tag_id) : attribute
}
tags_attributes_without_recycling= (existing_attributes + new_and_recycled_attributes)
end
alias_method_chain :tags_attributes=, :recycling
end
Это не проверено, поэтому никаких гарантий. Но это должно, по крайней мере, помочь вам найти решение.