【问题标题】:Ruby on Rails: Add subfolder in app directory with files specific to modelsRuby on Rails:在 app 目录中添加子文件夹,其中包含特定于模型的文件
【发布时间】:2021-09-23 01:55:28
【问题描述】:

我正在编写一个 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 文件应该针对 User 模型。表示此方法 send_reminder 应该可用于 User 的实例/对象

User.last.send_reminder 所以,问题是

  • 如何将通知程序文件夹的文件制作为特定于模型的文件(user.rb 模型文件在通知程序文件夹中有 user_notifier.rb 文件)
  • 这个文件 user_notifier.rb 方法如何用于用户模型

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

【问题讨论】:

  • 嗨@max,请看一下我已经提出的问题,关注点和命名空间(包括模型中)是可能的。但我想这样做,就像 rails 表现它自己的 MVC 模式一样。对于一个模型,不需要编写任何与该模型对应的控制器的配置。谢谢
  • 您可以使用命令rails runner "UserNotifier.new" 来检查UserNotifier 是否加载。如果您遇到错误,能否将rails runner "puts ActiveSupport::Dependencies.autoload_paths" 的结果发给我并告诉我您使用的是哪个版本的 Rails?

标签: ruby-on-rails ruby rubygems loading subdirectory


【解决方案1】:

如何将通知文件夹的文件制作为特定于模型的文件?

app文件夹下的所有代码都是在没有任何配置的情况下加载的。 您只需要尊重类的命名约定。 在这种情况下,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

【讨论】:

    【解决方案2】:

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

    发布它只是为了确保将来可能对其他人有所帮助。

    我为解决这个问题做了什么(为了将 gem 附加到一个模型中,我们在我们希望配置它的模型中添加 act_as_notifier)

    • 在通知器 gem 的 model_config.rb 类中
    • 拥有@model_class 并找到相应的通知程序类
    • 在notifier类中添加attr_accessor并用模型对象初始化
    • 还定义自定义 getter 和 setter 通知属性
    #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
    

    【讨论】:

    • 如果您认为在答案中需要以“gem 方式”将代码包含在 gem 中,您能否更新您的问题以明确将其添加到需求中?此外,您应该考虑使用关注点而不是元编程。在现有类中包含代码的 Rails 方式是关注点。如果您检查 rails 中 gems 的代码(active_record、active_support 等),在可能的情况下,关注点比元编程更受青睐,因为:代码更清晰,元编程会对性能产生相当负面的影响
    • @LéonardHenriquez 我投了你的票,回答很好(不幸的是,现在忘记将其标记为已接受)。但我只是更新答案以表明我们如何将它直接移动到 gem。我不想通过关注点和命名空间来做到这一点。我们正在将杂乱的代码与现有的应用程序分开。谢谢
    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多