首页 > 解决方案 > 访问类属性以在 Rails 关注中定义实例方法

问题描述

经过长时间的停顿后,我正在尝试元编程。我发现了一些问题,但无法获得解决我的问题的意见,所以我希望有人能启发我。

在 rails 5 应用程序中,我正在尝试编写一个提供类方法来设置配置选项的关注点。使用这些选项,我想定义实例方法。

module Base64Attachable
  extend ActiveSupport::Concern

  class_methods do
    attr_reader :base64_attachable_property

    private

    def base64_attachable(property)
      @base64_attachable_property = property
    end
  end

  included do
    # ?
  end
end

上面的问题在模型内部使用User

class User < ApplicationRecord
  include Base64Attachable
  base64_attachable :image
end

据我了解,关注点设置了在用户模型中调用的类方法。但是,我似乎无法base64_attachable_propertyincluded块内部根据它的值定义进一步的方法。self.class我以为我会在街区内找到我需要的任何东西included,但事实并非如此。

在这种情况下,目的是用于在用户模型中define_method定义 setter、getter 和其他方法。image

我在这里想念什么?

标签: ruby-on-railsrubyruby-on-rails-5

解决方案


included块在关注包含在类中的那一刻运行,该base64_attachable :image行尚未运行。

我建议你遵循官方宝石的做法。检查 ActiveStorage,例如https://github.com/rails/rails/blob/530f7805ed5790af1d472a041bc74089dc183f47/activestorage/lib/active_storage/attached/model.rb#L35。它在类方法中定义了依赖于该属性的方法(它使用 class_eval,但我想你也可以使用define_method):

  def has_one_attached(name, dependent: :purge_later)
    generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
      def #{name}
        @active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self)
      end
      def #{name}=(attachable)
        attachment_changes["#{name}"] =
          if attachable.nil?
            ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
          else
            ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
          end
      end
    CODE

    has_one :"#{name}_attachment", ......etc....

推荐阅读