Ruby on Rails:在 app 目录中添加子文件夹,其中包含特定于模型的文件

Ruby on Rails: Add subfolder in app directory with files specific to models

我正在编写一个 gem 来处理模型的所有类型的通知(短信、手机和浏览器通知)

在 app 目录下的 rails 项目中创建了新文件夹 'notifiers',其中包含类似

的文件
app/notifiers/user_notifier.rb

class UserNotifier < ApplicationNotifier
  def send_reminder
   {
     type: 'sms',
     content: 'hi everyone',
     recipients: [12134343,2342322,3434343]
   }
  end
end

此 user_notifier 文件应该针对用户模型。意味着此方法 send_reminder 应该可供 User

的 instance/object 使用

User.last.send_reminder 所以,问题是

这对于关注点和命名空间是可能的,但这会产生混乱的代码

如何将notifiers文件夹的文件制作成机型专用?

app文件夹下的所有代码都在没有任何配置的情况下加载。 您只需要遵守 class 的命名约定。 在这种情况下 UserNotifierapp/notifiers/user_notifier.rb 的正确名称。

如何将此文件 user_notifier.rb 方法提供给用户模型?

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  # your code

  def send_notification(notification_name, recipients)
    notifier = "#{self.class.name}Notifier".constantize.new()
    send(notification_name, recipients)
  end
end

# app/models/user.rb
class User < ApplicationRecord
  # your code

  # a method where you want to send a notification
  def foo
    send_notification(:reminder, [id])
  end
end

# app/notifiers/user_notifier.rb
class UserNotifier < ApplicationNotifier
  def reminder(recipients)
   {
     type: 'sms',
     content: 'hi everyone',
     recipients: recipients
   }
  end
end

感谢 Léonard,他发布了解决方案,但在编写 gem 时,我们需要处理来自 gem 的这些配置。因为当有人使用我们的 gem he/she 时,不必手动在 application_record.rb 中编写任何配置相关的逻辑。

张贴它只是为了确保将来它对其他人有帮助。

我为解决此问题所做的工作(将 gem 附加到我们要配置的模型中添加 act_as_notifier 的模型)

  • 在 model_config.rb class 的通知 gem
  • 有@model_class & 找到相应的通知程序class
  • 在notifierclass中添加attr_accessor并用model对象初始化
  • 同时定义自定义 getter 和设置器通知属性
#rails_notifier/model_config.rb
    def initialize(model_class)
      @model_class = model_class
      
      # get model corresponding notifier class
      # for User model class, there would UserNotifier class
      # under notifiers folder of app directory
      # getting notitifer class name
      notifier_class = "#{@model_class.name}Notifier"
      
      # Notifier class attribute set later set with model object
      attribute_name = @model_class.name.underscore
      
      # register a `notifier` method in model class
      # 'method_name' is a method of notifier class
      # and options hash contain sender
      @model_class.class_eval do
        define_method(:notifier) do |method_name, options|
          # create notifier class object
          notifier_ = notifier_class.constantize.new

          # define setter for notifier attribute
          notifier_.send(:define_singleton_method, "#{attribute_name}=".to_sym) do |value|
            instance_variable_set("@" + attribute_name.to_s, value)
          end

          # define getter for notifier attribute
          notifier_.send(:define_singleton_method, attribute_name.to_sym) do
            instance_variable_get("@" + attribute_name.to_s)
          end

          # self point to the object of model
          # e.g User.last.notifier(:send_reminder), slef = User.last
          # set notifier attribute with model object
          notifier_.send("#{attribute_name}=".to_sym, self)
          notifier_hash = notifier_.send(method_name)
          RailsNotifier.notify(notifier_hash) if notifier_hash.present?
        end
      end
    end