@Fly3110
web developer

Почему от положения include в модели зависит поведение HABTM ассоциации?

Всем привет.

Последний час я потратил на дебаг очень странного поведения рельсов.

Есть следующие модели

app/models/user.rb
class User < ApplicationRecord
  ...
  has_many :images
  has_many :videos
  ...
  has_many :tags
  ...
end


app/models/image.rb
class Image < ApplicationRecord
  ...
  belongs_to :user
  ...
  has_and_belongs_to_many :tags
  ...
  include TagsFunctions
  ...
end


app/models/video.rb
class Video < ApplicationRecord
  ...
  include TagsFunctions
  ...
  belongs_to :user
  ...
  has_and_belongs_to_many :tags
  ...
end


app/models/concerns/tags_functions.rb
module TagsFunctions
  extend ActiveSupport::Concern

  # хак для заполнения тэгов у вновь создаваемых моделей
  included do
    attr_accessor :tags_after_creation

    after_create -> { self.tags_string = tags_after_creation if tags_after_creation.present? }
  end

  def tags_string
    tags.pluck(:text).join(',')
  end

  def tags_string=(value)
    unless user  # Если пользователь еще не заполнен, запоминаем тэги и выходим
      @tags_after_creation = value
      return
    end

    @tags_after_creation = ''
    self.tags = []
    value.to_s.split(',').map(&:strip).each do |tag_text|  # разбиваем строку, используя запятую, как разделитель
      tag = user.tags.find_or_create_by(text: tag_text)  # получаем/создаем нужные тэги
      self.tags << tag                                # записываем тэги в ассоциацию
    end
  end
end


Выполняем вот такой код:
user = User.first
tags_string = 'test'
image = user.images.create(tags_string: tags_string)
video = user.videos.create(tags_string: tags_string)

В результате, в video.tags мы имеем два одинаковых (дублирующихся) тега.
В image.tags - один тег.

Если выполнить код вот так:
user = User.first
tags_string = 'test'
image = Image.create(user: user,  tags_string: tags_string)
video = Video.create(user: user, tags_string: tags_string)

то все в порядке, один тег и там и там.

И теперь еще большая мистика (для меня). Если в video.rb переместить include TagsFunctionsпосле has_and_belongs_to_many :tags, то все начинает работать правильно и с первым вариантом кода.

Мне казалось, что я хорошо знаю рельсы, но это поведение ставит меня в тупик.
Версия рельсов: 5.1.1

Кто может объяснить такое поведение?
  • Вопрос задан
  • 78 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы