扩展活动存储::附件 - 添加自定义字段



我想扩展类ActiveStorage::Attachment并添加一个枚举属性以显示附件。

我最初的方法是在\app\models目录中创建一个新的文件attachment.rb,如下所示。

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

扩展在初始化期间加载到扩展.rb 中

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

不幸的是,它只能部分工作: 而枚举方法publicly_visible?privately_visible呢?在视图中可用,在控制器中不可用。当调用控制器中的任何方法时,枚举似乎已经消失了。我收到"无方法错误 - 未定义的方法"错误。 令人惊讶的是,一旦枚举方法在控制器中被调用一次,它们在视图中也不再可用。 我假设 ActiveStorage::Attachment 类会动态重新加载,并且扩展会丢失,因为它们仅在初始化期间添加。

有什么想法吗?

我假设 ActiveStorage::Attachment 类会动态重新加载,并且扩展名会丢失,因为它们仅在初始化期间添加。

你是对的。在应用程序启动后和每次重新加载代码时,使用Rails.configuration.to_prepare混合模块:

Rails.configuration.to_prepare do
ActiveStorage::Attachment.send :include, ::ActiveStorageAttachmentExtension
end

正如我的评论中所述,它需要包含以下内容的文件app/models/active_storage_attachment.rb

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

然后,您还需要将整数类型的列可见性添加到表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的用户。

我可以通过user.avatar.attachment.inspect访问active_storage_attachments表,例如返回#<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数组转换(我仍然想知道为什么(。

一种可能的解决方法是在用户模型中定义一个类似于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

这在 Rails 6 中对我有用。

# frozen_string_literal: true
module ActiveStorageAttachmentExtension
extend ActiveSupport::Concern
included do
has_many :virus_scan_results
end
end
Rails.configuration.to_prepare do
ActiveStorage::Attachment.include ActiveStorageAttachmentExtension
end

如果其他人遇到这种情况,我不喜欢这里输入的解决方案,所以我想出了另一种方法。不是 100% 确定它是否与Rails.configuration.to_prepare解决方案一样好,但我喜欢它的一点是它只是app/models目录中的一个文件,所以在项目中其他地方的配置文件中没有魔术。

我制作了一个名为:app/models/active_storage/attachment.rb的文件。因为它在您的项目中,所以它的加载优先级高于 Gem 版本。然后在里面我们加载 Gem 版本,然后使用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?

最新更新