1

我有一个简单的多态评论模型,定义如下:

class Comment < ActiveRecord::Base
  include Rails.application.routes.url_helpers
  if Rails.env.production?
    default_url_options[:host] = "www.livesite.org"
  else  
    default_url_options[:host] = "livesite.dev"
  end

  attr_accessible :content
  attr_accessible :commentable_id, :commentable_type
  belongs_to :commentable, polymorphic: true
  belongs_to :user

  validates_presence_of :content

  after_create :subscribe_to, :notify_subscribers

  private

    def subscribe_to
      commentable.rdb[:subscribers].sadd user_id
    end

    def notify_subscribers
      subscriber_ids = commentable.rdb[:subscribers].smembers.to_a
      subscriber_ids.delete user_id.to_s
      # remove the author's id from the array
      subscribers = User.where(id: subscriber_ids)
      subscribers.each do |subscriber|
        subscriber.notifications.create(
          content:        "<a href='#{ user_url(user) }'>#{user.name}</a> commented about <a href='#{ polymorphic_url(commentable) }'>#{commentable.name}</a>",
          read:           false,
          notifyable:     commentable
        )
      end
    end

end

你可以看到我使用了一点 Redis 魔法来为特定的评论创建一些订阅者,但我的问题是如何polymorphic_url在这里抽象出模型上的部分。在模型级别拥有它似乎很奇怪。有更好的方法吗?把它放在这里意味着我需要包括url_helpers并且正在与 Capybara 合作并测试一个真正的 palava。

供参考,Notification.rb 如下:

class Notification < ActiveRecord::Base
  attr_accessible :subject, :read, :user_id, :notifyable

  belongs_to :user
  belongs_to :notifyable, polymorphic: true

  default_scope order('created_at DESC')

end
4

2 回答 2

1

您可以将该通知逻辑上移到服务对象中(在此处阅读更多内容)。

- app
  - models
  - views
  - controllers
  - services # put service objects here

您的新服务对象将单独负责执行通知逻辑,您至少需要传入您的评论模型,并包含或依赖注入 url 帮助程序

class CommentNotificationService
  def initialize(comment, url_provider)
    @comment, @url_provider = comment, url_provider
  end
end

在您的控制器中实例化它,例如:

class CommentsController < ApplicationController
  def create
    comment = Comment.new params[:comment]
    service = CommentNotificationService.new comment, Rails.application.routes.url_helpers

    if comment.save
      service.do_the_work
    else
      ...
  end
end

现在,在服务的do_the_work方法中,您可以执行与旧模型notify_subscribers方法相同的操作。依赖注入部分不是最好的(特别是我写它的方式),但它是一个很好的起点。您可以像在模型中那样在服务对象中包含 url_helpers。

服务对象方法通过消除必须执行通知的额外责任,使您的模型精简且易于测试。然后您可以轻松测试通知逻辑。

于 2013-07-01T16:34:42.930 回答
0

这些属性应该在相应的环境文件中设置(例如config/environments/development.rb):

config.after_initialize do
  Rails.application.routes.default_url_options[:host] = 'livesite.dev'
end    

production.rb对具有相应主机名的环境文件执行相同操作。

于 2013-07-01T16:20:30.857 回答