読者です 読者をやめる 読者になる 読者になる

アナログ金木犀

つれづれなるまままにつれづれする

複数ActiveRecordにまたがった処理をどこに書くか

Ruby on Rails

これってみんなどこに書いてるんですかね?

私自身は嗜む程度には書いてきましたが、ゴリゴリやってきたってわけでもないのでお手柔らかにお願いしますm m

今日通知処理を実装してました。

Qiitaとか例にすると、自分が書いた記事を誰かがストックしたり、コメントしたり、Twitterでつぶやいたりすると右上に出てくるあの数字のやつです。

たとえば、僕の記事を誰かがストックした場合って大雑把におそらく下記の2つの処理が走るようになってるのだと思います。

  • Stock.createが走る
  • Notification.createが走る

このときこれらの処理をどこに書きますか?ってのを考えてみました。

で、正直言うとまだすっきりしてないので良い方法あれば知りたいです。

1. Controllerに書く

StocksController.createのところで、二つの処理を書く感じです。

これはちょっと自分は避けたいかなと思いました。

というのも、他の場所でもStock.createが走る動線があった場合にまた、二つの処理をかかねばらなずDRYから外れがちになりそうなので。

この二つを一つのセットとして、ドメインレイヤーに持っていきたい。

2. Stockに書く

Stockの中にNotification.createの処理を持たせるパターンです。

これも自分は避けたいなぁと思いました。

理由は、StockというクラスがNotificationの責務を持つべきではないと思うからです。

3. rails-observersを使う

StockObserverを作り、after_createの中でNotification.createをする。

今回実はこれを採用しました。一番すっきりする設計かなと思います。

ただ、rails-observersって4.0でcoreから抜けてpluginになったっていう経歴があって、その経緯がよくわかってないので本当に使っていいのか少し心配。

とはいえ、deprecatedってわけじゃなくて(?)pluginに切り離しただけだろうから、まぁ使ってもいいだろうと思いました。

4. Concernsを使う

observersではなくてConcernsで同じことができるようです。

Rails Observer Alternatives for 4.0

同じことはできるんですけど、Concernの責務があやむやになってる感あるなぁという感想。

あぁでも、ちょうど書いてる途中で思いついたんですが、こういう風にNotificationのモジュールを作って

module NotificationModule
  extend ActiveSupport::Concern

  included do
    after_save :notification
  end

  def notification
     ...
  end
end

ActiveRecordにincludeしてあげるのは便利そうだ。

class Stock < ActiveRecord::Base
  include NotificationModule
  :
end
class Comment < ActiveRecord::Base
  include NotificationModule
  :
end

ただでもやっぱり、 Stockの中にNotificationをincludeしてるのは違和感あるかも。。


今回に限ってはrails-observersが現状だと一番きれいにかけるなぁという印象でした。

ただ、性質の違った事例の場合はまた答えが違うかも。

もっと良い方法ある方、ご教授いただけたら幸いです。