Расширение ActiveStorage :: Attachment - Добавление пользовательских полей - PullRequest
0 голосов
/ 09 июня 2018

Я хочу расширить класс ActiveStorage :: Attachment и добавить атрибут enum для видимости вложений.

Мой первоначальный подход состоял в том, чтобы создать новый файл attachment.rb в каталоге \ app \ models следующим образом.

class ActiveStorage::Attachment < ActiveRecord::Base
    enum visibility: [ :privately_visible, :publicly_visible]
end

Это не работает.

Любые предложения приветствуются.Какой способ расширения классов в Rails?

Обновление

У меня есть решение, которое работает частично сейчас.Для этого я создал расширение active_storage_attachment_extension.rb и поместил его в \ lib

module ActiveStorageAttachmentExtension

  extend ActiveSupport::Concern

  included do
    enum visibility: [ :privately_visible, :publicly_visible]

    def describe_me
      puts "I am part of the extension"
    end

  end
end

Расширение загружается во время инициализации в extensions.rb

ActiveStorage::Attachment.send(:include, ::ActiveStorageAttachmentExtension)

К сожалению, это толькоработает частично: в то время как методы enum publicly_visible?а private__visible?доступны в представлениях, они не доступны в контроллере.При вызове любого из методов в контроллере перечисление, кажется, исчезло.Я получаю ошибку "NoMethodError - неопределенный метод".Удивительно, но как только методы enum вызываются один раз в контроллере, они также больше не доступны в представлениях.Я предполагаю, что класс ActiveStorage :: Attachment перезагружается динамически и что расширения теряются, поскольку они добавляются только во время инициализации.

Есть идеи?

Ответы [ 3 ]

0 голосов
/ 10 июня 2018

Я предполагаю, что класс ActiveStorage :: Attachment перезагружается динамически и расширения теряются, поскольку они добавляются только во время инициализации.

Вы правы.Используйте Rails.configuration.to_prepare, чтобы смешать модуль после загрузки приложения и каждый раз, когда код перезагружается:

Rails.configuration.to_prepare do
  ActiveStorage::Attachment.send :include, ::ActiveStorageAttachmentExtension
end
0 голосов
/ 11 января 2019

Если кто-то столкнется с этим, мне не понравятся решения, введенные здесь, поэтому я нашел другой способ.Не на 100% уверен, что оно так же хорошо, как решение Rails.configuration.to_prepare, но мне нравится то, что это всего лишь один файл в каталоге app/models, так что никакого волшебства не происходит в файлах конфигурации где-то еще в вашем проекте.

Я создаю файл с именем: app/models/active_storage/attachment.rb.Поскольку он находится в вашем проекте, он имеет приоритет загрузки над версией Gem.Затем внутри мы загружаем версию Gem, а затем monkeypatch, используя class_eval:

active_storage_gem_path = Gem::Specification.find_by_name('activestorage').gem_dir
require "#{active_storage_gem_path}/app/models/active_storage/attachment"

ActiveStorage::Attachment.class_eval do
  acts_as_taggable on: :tags
end

Немного неприятная часть - найти оригинальный файл, так как мы не можем найти его обычно, потому что наш новый файл имеет приоритет,Это не нужно в производстве, так что вы можете поставить if Rails.env.production?, если хотите, я думаю.

0 голосов
/ 09 июня 2018

Как уже упоминалось в моем комментарии, требуется файл app/models/active_storage_attachment.rb с таким содержимым:

class ActiveStorageAttachment < ApplicationRecord
  enum visibility: [ :privately_visible, :publicly_visible]
end

Затем вам также нужно добавить видимость столбца типа integer в таблицу active_storage_attachments.

class AddVisibilityToActiveStorageAttachments < ActiveRecord::Migration[5.2]
  def change
    add_column :active_storage_attachments, :visibility, :integer

  end
end

Доступ к новому столбцу ActiveStorageAttachment

Я делаю пример на моей модели: у меня есть пользователь, который has_one_attached: avatar.

Я могу получить доступ к таблице active_storage_attachments через user.avatar.attachment.inspect, который возвращает, например, #<ActiveStorage::Attachment id: 1, name: "avatar", record_type: "User", record_id: 1, blob_id: 3, created_at: "2018-06-03 13:26:20", visibility: 0>.

Обратите внимание, что значение столбца visibility является чистым целым числом, не преобразованным массивом visibility (IЯ все еще задаюсь вопросом, почему).

Один из возможных обходных путей - определить метод, подобный avatar_attachment в модели пользователя, например:

class User < ApplicationRecord
  has_one_attached :avatar

  def avatar_attachment
    ActiveStorageAttachment.find_by(name: 'avatar', record_type: 'User', record_id: self.id)
  end
end

Теперь user.avatar_attachment.inspect возвращает #<ActiveStorageAttachment id: 1, name: "avatar", record_type: "User", record_id: 1, blob_id: 3, created_at: "2018-06-03 13:26:20", visibility: "privately_visible">

Теперь доступны все методы, связанные с массивом видимости.Также работает обновление записи:

user.avatar_attachment.publicly_visible! # => true
...