

railsの名前空間について調べると、名前の衝突(同名での定義)を防ぐというのが目的という情報しか出てきません。

[code]

    module Admin
     class User
      #メソッドなど
     end
    end
    
    module Guest
     class User
      #メソッドなど
     end
    end
    
[/code]

しかし、例えばパソコンでファイルを整理するさいに同系統のものを同じフォルダに整理したりするのと同じ感じで、同系統のファイルを整理する目的で使ってもよいのでしょうか？

例えば以下のような感じです。  
Aという機能に関係したservice一覧と、Bという機能に関係したservice一覧には一切、名前の重複はありません。

[code]

    app/service/機能A/Aという機能に関係したservice一覧
    app/service/機能B/Bという機能に関係したservice一覧
    
[/code]


CC BY-SA 4.0
2022-02-17T22:54:11.077
86424
2022-02-19T01:32:22.643
2022-02-18T11:35:45.240
40650
40650
question
ruby-on-rails
railsの名前空間の目的についての疑問


RubyとRailsでの話がごっちゃになっているように思います。まずはそれらを整理してから話していきます。

## プログラミング言語における「名前空間」

「名前空間」というのはプログラミング言語一般で使用される機能で、主な目的はお調べしたとおり「名前の衝突を防ぐ」と言うものです。Cのような古い言語では名前空間という機能を言語として実装していなかったため、二つの既存のプログラムをくっつけて一つのプログラムに使用としたとき、関数名等が被ってしまい既存のプログラムのコードの修正が必要になったと言うことがありました。その反省を踏まえ、その後に開発された言語、例えばC++では`namespace`というキーワードを使って「名前空間」を作成することで、関数名等の衝突などを防ぐようにしました。他の言語でも同じように「名前空間」の機能を搭載していきますが、どのようにして提供するかは言語によって異なります。例えば、JavaのパッケージやJavaScriptのモジュールと言った機能も「名前空間」の機能を提供する実装の一つです。

## Rubyのおける「名前空間」とモジュールの関係

Ruby自体には「名前空間」という名前の機能がありません。しかし、「名前空間」を実現出来ないというわけではありません。モジュールが「名前空間」の機能を提供するとなっています。

まず、勘違いしてはいけないのは、モジュールは「名前空間」のため **だけ** の機能ではないことです。他のクラスやモジュールにMix-
inしたり、オブジェクトそのものの拡張(`extend`)したり、再定義(`refine`)の機能を使うために`using`したりします。それら多くの機能の一つとして、「名前空間」の機能があると言うことです。なお、クラスもモジュールを拡張しているため、同じように「名前空間」に使用することができます。

名前空間を作るかどうか、どのように使うかは、そのプログラムは何か、また、設計指針はどうなっているかによります。例えば、gemで提供されるライブラリは、一番トップでライブラリ名の名前空間で分けて、他のライブラリと被らないようにするのが通例です。これはライブラリが他のプログラムと一緒になる可能性があるため、適切な名前空間を設けていないと名前衝突が発生してしまうからです。逆に言うと、ライブラリでも無く、他のプログラムと一緒になるようなことも無いような、それこそ書き捨てなプログラムなら、わざわざ名前空間を作る必要は無いと言えます。

## RailsにおけるRubyの「名前空間」

前節まではRuby一般の話でRailsの話ではありませんでした。これがRailsになると自由に何でもしていいのかというわけではなくなります。なぜなら、Railsには流儀というか設計指針というか、名前空間の分け方の指針みたいな物があるからです。

`User`モデルの一覧を読み込む"/users"というアクセスを考えています。"/users"へのアクセスは"/app/controllers/users_controller.rb"にある`UsersContoroller`コントローラーの`index`メソッドを呼び出します。この`UsersContoroller`はどこかのモジュールの中ではなく、トップレベルに定義されている必要があります。一覧はいいが、作成や編集は管理者だけなので、わかりやすいように"/admin/users/new"で新規作成画面を出すとします。"/admin/users/new"へのアクセスは、"/app/controllers/admin/users_controller.rb"にある`Admin::UsersContoroller`コントローラーの`new`メソッドが呼び出します。こちらの`Admin::UsersContoroller`は`Admin`モジュールに名前空間にあります。クラス名は一緒でも先程の`UsersContoroller`とは別物です。このように同じクラス名でも全く別のクラスとして定義できるようになります。

もちろん、各パスを全く別のコントローラに紐付けるもできます。ただ、その場合は"config/routes.rb"で追加のオプションを設定する必要があります。必要に迫られない限り、やるできではないでしょう。

このように、Railsではモデルやコントローラー等をどこに置くのか、その時はモジュールの中か、それともトップレベルにするのかが決まっています。通常のモデルやコントローラーのクラスはトップレベルですが、`ralis
generate`の時に"親の名前/モデル名"と言うような形で作成すると、モジュールで名前空間を形成して、同じ名前でも別々のモデルやコントローラを作ることができます。

## Railsの「コントローラーの名前空間」

上記の話とは別にRailsには「コントローラーの名前空間」というものがあります。実は先程でてきた"/admin/users/new"は"contfig/routes.rb"でどうなるかと言うと、`rails
generate controller admin/users new`と実行して作ってみるとわかりますが、

[code]

    Rails.application.routes.draw do
      # ...
      namespace :admin do
        get 'users/new'
      end
      # ..
    end
    
[/code]

といった形になります(ほかに`create`等もあれば、`resources`に書き替えても言いでしょう)。この`namespace`メソッドが実現するのが「コントローラーの名前空間」です。似たような機能として、`scope`を使う方法もありますが、こちらはパスだけが変わるだけで、名前空間は作られず、モジュールもトップのままです。

## 最後の質問への回答について

最後の機能のservice一覧についてです。

`Service`モデル(サービス)と`Mechanism`モデル(機能)があるという話でいいでしょうか？そして、機能によって提供するサービスが異なる、つまり、機能はサービスを`has_many`している、逆に、サービスを提供する機能は一つだけ、つまり、サービスは機能に`belongs_to`していると言う関係でしょうか？

上記の前提で、機能毎にサービス一覧を出すコントローラーの話という場合は次のように[ネストしたリソース](https://railsguides.jp/routing.html#%E3%83%8D%E3%82%B9%E3%83%88%E3%81%97%E3%81%9F%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9)を使うのがいいかと思います。

[code]

    Rails.application.routes.draw do
      # ...
      resources :mechanisms do
        resources :services
      end
      # ..
    end
    
[/code]

"/mechanisms/:mechanism_id/services"と言うパスで`ServicesController`コントローラーを呼び出します。これは名前空間ではないので、`Mechanisms::ServicesController`
**にはならない** ことに注意してください。

コントローラーの話ではなく、単にライブラリ的なクラスやモジュールを作るという話であれば、名前空間をどうするかは自由です。作っても良いですし、作らなくても良いです。ただ、将来その部分をgemとして独立したライブラリにするなどの予定であれば、その時のライブラリ名になるであろう名前のモジュールをトップにおいて名前空間を分けた方がいいでしょう。ほかにも、関連する物毎にまとまっていれば、どこにあるかがわかりやすくなるという場合もあります。

なお、"app"にはモデル、コントローラー、ヘルパー等の決まった物以外は置かない方がいいです。"app"内のパス構成は、Railsで決められた通りであることが前提となっているため、将来のバージョンアップで予期せぬ衝突が発生する可能性があります。それらではない自作のクラスやモジュールは"lib"内に置く方が良いでしょう。


CC BY-SA 4.0
2022-02-19T01:32:22.643
86448
2022-02-19T01:32:22.643
7347
86424
answer