Ensuring restrictions on uniqueness in a nested form

I try not to deal with defaults here and use the built-in Rails support for nested attributes (from http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes ). I put Things with Tags, and all the works are inflated, and for each Thing I have a form with a nested field that creates a new tag by name. The problem is that I have to make sure that each tag has a unique name. Instead of creating a new tag, if the user enters the name of an existing one, I need to create an associated element with this previously existing tag. How to do it?

+3
source share
2 answers

This is probably the best way to do this, but it concerns what I can come up with now.

The has_many (: through) association accepts_nested_arguments_for uses a virtual attribute assignment #{association}_attributesto work with magic. It expects an array of hashes, where each hash contains attribute keys and their values. Any hashes with an identifier will be updated (or deleted if there is a key :_deletewith a value of true). Any hashes that do not have an identifier will be used to create new elements of this association. Thus, the key is to intercept the call tags_associations=and check any hashes that do not have identifiers for an existing tag with the same name, and replace it with the entry that attribute_tags will use to link the existing tag, NB has_one belongs_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

, . .

+1

Thing tags_attributes =, Tag.find_or_create

def tags_attributes=(attributes)
  attributes.each do |attr|
    Tag.find_or_create_by_name(attr[:name])
  end
end

, , .

+1

Source: https://habr.com/ru/post/1734360/


All Articles