Search code examples
ruby-on-railsrubynested-attributesruby-on-rails-5

Rails. Many to many set relation via nested attributes


I've been trying to figure out how to set has_many, through: relation using nested attributes.

I have the following models:

user.rb

class User < ApplicationRecord
   has_many :user_tags
   has_many :tags, through: :user_tags

   accepts_nested_attributes_for :user_tags,
                            allow_destroy: true,
                            reject_if: :all_blank
end

user_tag.rb

class UserTag < ApplicationRecord
  belongs_to :tag
  belongs_to :user

  accepts_nested_attributes_for :tag

  validates :tag, :user, presence: true
  validates :tag, :uniqueness => {:scope => :user}
  validates :user, :uniqueness => {:scope => :tag}
end

tag.rb

class Tag < ApplicationRecord
  has_many :user_tags
  has_many :users, through: :user_tags

  validates :title, presence: true, uniqueness: true
end

Related schema

  create_table "user_tags", id: :integer, force: :cascade do |t|
    t.integer  "user_id"
    t.integer  "tag_id"
    t.index ["tag_id"], name: "index_user_tags_on_tag_id", using: :btree
    t.index ["user_id"], name: "index_user_tags_on_user_id", using: :btree
  end

  create_table "tags", id: :integer, force: :cascade do |t|
    t.string   "title"
    t.string   "language"
    t.integer  "type"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

All tags are predefined, and cannot be modified. I need only set and destroy relation between tags and users in model user_tag, in user's create/update actions via nested attributes.

Something like:

params = { user: {
      user_tags_attributes: [
          { id: 1, _destroy: '1' }, # this will destroy association
          { tag_id: 1 }, # this will create new association with tag, which id=1 if tag present
          { tag_title: 'name' } # this will create new association with tag, which title='name' if tag present
      ]
  }}

user.update_attributes(params[:user])

Exact problem is that I can't create ONYL association, but I can create or update tags through associations.

I'm using Rails 5.0


Solution

  • I've found a solution of my problem. I have mistake in UserTag validations.

    I've changed

      validates :tag, :uniqueness => {:scope => :user}
      validates :user, :uniqueness => {:scope => :tag}
    

    to

      validates :tag_id, :uniqueness => {:scope => :user_id}
      validates :user_id, :uniqueness => {:scope => :tag_id}
    

    and tag assignment is working.

    Remans to find solution how to destroy association by tag_id, without association id