🚋

dev.toのapp以下を見る

2020/10/24に公開

著名なオープンソースRailsアプリのapp/以下を見る の「dev.to」の項目から一部引用:

他のRailsアプリで見慣れたものも多いものの、具体的にどういう基準でディレクトリを追加しているのかについてはドキュメントを見てもよくわからなかったので、各位頑張って調べて欲しい…という気持ちです。

ということで調べてみました!
以下アルファベット順で各ディレクトリについて述べていきます。

black_box

BlackBloxというクラスが1つあるだけ。
BlackBloxクラスはクラスメソッドのみ定義されていて、内容は次のような値を計算する系のもの。

  • article_hotness_scoreメソッド
    • 記事がホットかどうかのスコアを計算
  • calculate_spaminessメソッド
    • ユーザーのスパム性を計算
  • comment_quality_scoreメソッド
    • コメントの質のスコアを計算

クラスが1つですし、ディレクトリを用意する必要があるのかは疑問ですね。

dashboards

管理画面を作成するgem administrate で、画面をカスタマイズするためのクラスの置き場所。

decorators

View Models的な、decoratorクラスの置き場所。
前はdraper というgemを使っていたけど、draperはmagicなので、Rails5.1から追加された delegate_missing_to を使って、シンプルな形に実装したとのこと。https://github.com/forem/forem/pull/6040

参考にArticleDecoratorのコードを一部抜粋してコメントを付与:

app/decorators/article_decorator.rb
# 記事の公開状況に応じたパスを生成するメソッド
def current_state_path
  published ? "/#{username}/#{slug}" : "/#{username}/#{slug}?preview=#{password}"
end

# タイトルに長さに応じたcssのclass名を生成するメソッド
def title_length_classification
  if title.size > 105
    "longest"
  elsif title.size > 80
    "longer"
  elsif title.size > 60
    "long"
  elsif title.size > 22
    "medium"
  else
    "short"
  end
end

errors

StandardErrorを拡張した、各種Errorクラスの置き場所。

例:

  • PaymentsError
  • UnauthorizedError

fields

管理画面を作成するgem administrateFieldクラスの置き場所。

labors

労働?

例:

  • ArticleSuggester
    • 記事ページの下部のオススメ記事を取得するもの
  • EmojiConverter
    • markdown内の:hoge:のような表記を絵文字のコードに変換するもの

servicesに近い?
結構重たそうな仕事をしている?

lib

moduleやクラスメソッドなどの、インスタンス化せずに使うクラスの置き場所。

例:

  • URL module
    • 設定されているドメイン名やプロトコルを反映した各種URLを生成するもの
  • Constants::Role
    • ユーザのBanTrustedなどのroleの配列を保持

liquid_tags

template engineのgem liquid のタグの置き場所

mailers

Rails標準の Action Mailer の置き場所。

middlewares

Rackミドルウェア の置き場所。

policies

authorizationのgem pundit で使う、Policyクラスの置き場所。

queries

admin系の複雑なActiveRecord::Relationインスタンスを生成する役割のクラスの置き場所。
2つしかクラスがないので、それほど活用されていない模様。

例:

app/queries/admin/users_query.rb
module Admin
  class UsersQuery
    def self.call(relation: User.registered, options: {})
      role, search = options.values_at(:role, :search)

      relation = relation.with_role(role, :any) if role.presence
      relation = search_relation(relation, search) if search.presence

      relation.order(created_at: :desc)
    end

    def self.search_relation(relation, search)
      relation.where("users.name ILIKE :search OR
      users.username ILIKE :search OR
      users.github_username ILIKE :search OR
      users.email ILIKE :search OR
      users.twitter_username ILIKE :search", search: "%#{search.strip}%")
    end
  end
end

sanitizers

gem rails-html-sanitizer のカスタマイズ用のクラスの置き場所。

services

幅広い役割のクラスの置き場所。

たとえば、次のようなArticleモデルを扱うようなクラス群があります。

  • module Articles
    • Builderクラス
      • newの画面でデフォルトのacricleをbuildするもの
    • Creatorクラス
      • articleをsaveするときの様々な処理を担う
    • Destroyerクラス
      • articleをdestroyするときの様々な処理を担う
    • Feedクラス
      • latest_feeddefault_home_feed のような様々な種類のarticleの一覧を生成するもの

他には、slackにメッセージを送る Slack::Announcer クラスのようなものもあります。
クラスの数も多く、かなり活用されているディレクトリです。

uploaders

ファイルのアップロード処理を扱うgem carrierwave で使用する Uploader クラスの置き場所。

view_objects

decoratorsに近い役割?
2つしかクラスがないので、あまり活用されていない模様。

workers

バックグラウンド処理を実現するgem sidekiqWorkerクラスの置き場所。

まとめ

大体のディレクトリがgemで使うクラスの置き場所でした。
それ以外ではservicesがクラスの数的にも、重要な役割を担っているようです。

Discussion