Rails(5)namespace でファイルを分ける方法

## はじめに
1つのRailsアプリケーションの内で、管理画面のコードをadminみたいなネームスペースでわけて管理する事がありました。
その際の事を忘れないようにメモ。
今回ネームスペースで分けるのは以下の3つです。
`admin`、`staff`、`participant`

※名前は適当なので、ご勘弁ください。

環境 
Rails 5.1.3
Ruby 2.4.0

## viewに各ネームスペースのディレクトリの作成
以下のディレクトリを作成
./app/views/admin
./app/views/staff
./app/views/participant

## layoutsディレクトリ内に各ネームスペースのディレクトリを作成
以下のディレクトリを作成
./app/views/layouts/admin
./app/views/layouts/staff
./app/views/layouts/participant

## layoutsディレクトリ内に各ネームスペースのhtml.erbを作成する

```html+erb:./app/views/layouts/admin.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>namespace - admin</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
<body>
<% content_for :content do %>  
  <%= yield %>
<% end %>
<%= render template: "layouts/application" %>
</body>
</html>
```
他もそれぞれつくる
./app/views/layouts/staff.html.erb
./app/views/layouts/participant.html.erb

## controllerに各ネームスペースのディレクトリの作成
./app/controllers/admin
./app/controllers/staff
./app/controllers/participant

## 各ネームスペースのcontrollerのフォルダ内でbase.rbを作成

```ruby:./app/controllers/admin/base.rb
class Admin::Base < ApplicationController
	 layout 'admin'
end
```

## application.html.erbを修正

application.htmlファイル全部を以下に書き換える

```ruby:./app/views/layouts/application.html.erb
<%= content_for?(:content) ? yield(:content) : yield %>
```

## 試しにコントローラを作ってみる

```
rails generate controller admin/TestAdmin new
```

```
create  app/controllers/admin/test_admin_controller.rb
       route  namespace :admin do
    get 'test_admin/new'
  end
      invoke  erb
      create    app/views/admin/test_admin
      create    app/views/admin/test_admin/new.html.erb
      invoke  test_unit
      create    test/controllers/admin/test_admin_controller_test.rb
      invoke  helper
      create    app/helpers/admin/test_admin_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/admin/test_admin.coffee
      invoke    scss
      create      app/assets/stylesheets/admin/test_admin.scss
```

他もそれぞれつくる

```
rails generate controller staff/TestStaff new
```

```
rails generate controller participant/TestParticipant new
```


## root.rbがネームスペースでルーティングされている事を確認

```ruby:./config/routes.rb
  namespace :admin do
    get 'test_admin/new'
  end
```

## 作成したコントローラーの修正

base.rbを継承させるように修正する

```ruby:./app/controllers/admin/test_admin_controller.rb
class Admin::TestAdminController < ApplicationController
  def new
  end
end
```

↓


```ruby:./app/controllers/admin/test_admin_controller.rb
class Admin::TestAdminController < Admin::Base
  def new
  end
end
```

他のコントローラも修正
./app/controllers/participant/test_participant_controller.rb
./app/controllers/staff/test_staff_controller.rb


## ブラウザで表示の確認

/admin/test_admin/new
![admin_test.png](https://qiita-image-store.s3.amazonaws.com/0/54809/ed47f23b-35a2-aa92-561c-f997b320ef46.png)

/staff/test_staff/new
![staff_test.png](https://qiita-image-store.s3.amazonaws.com/0/54809/600ffb15-b1f0-dba3-1889-7479cef2674e.png)

/participant/test_participant/new
![participant_test.png](https://qiita-image-store.s3.amazonaws.com/0/54809/42e6746c-5045-6f56-4ef8-b7a664ba35cf.png)

## 各ネームスペース毎にheaderとfooterを設定する

### _header.html.erbと_footer.html.erbの準備をする

以下のようにheaderとfooterの部分テンプレート作成する

```html+erb:./app/views/layouts/admin/_header.html.erb
<header>
  <p>admin_header</p>
</header>
```

```html+erb:./app/views/layouts/admin/_footer.html.erb
<footer>
  <p>admin_footer</p>
</footer>
```

他のそれぞれ作る
./app/views/layouts/staff/_header.html.erb
./app/views/layouts/staff/_footer.html.erb

./app/views/layouts/participant/_header.html.erb
./app/views/layouts/participant/_footer.html.erb


### _header.html.erbと_footer.html.erbを呼び出す


```html+erb:./app/views/layouts/admin.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>namespace - admin</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
<body>
<% content_for :content do %>
  <%= render 'layouts/admin/header' %>
  <%= yield %>
  <%= render 'layouts/admin/footer' %>
<% end %>
<%= render template: "layouts/application" %>
</body>
</html>
```

他もそれぞれ呼び出す
./app/views/layouts/staff.html.erb
./app/views/layouts/participant.html.erb

### ブラウザで確認
/admin/test_admin/new
![admin_header_footer.png](https://qiita-image-store.s3.amazonaws.com/0/54809/ff2362a4-5e9a-77d1-d638-7c606a21d454.png)

/staff/test_staff/new
![staff_header_footer.png](https://qiita-image-store.s3.amazonaws.com/0/54809/b139a4aa-3ea1-bd71-ab83-7a2fe42116bd.png)

/participant/test_participant/new
![participant_header_footer.png](https://qiita-image-store.s3.amazonaws.com/0/54809/4348409e-a4a4-5a45-e396-2cdb196cfe18.png)

## CSSの振り分けを行う

### cssファイルの作成

application.cssとは別にadmin.cssを以下のように作成してください

```css:./app/assets/stylesheets/admin.css
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree ./admin
 */
```

他もそれぞれcssファイルを作ります。

```css:.app/assets/stylesheets/staff.css
*= require_tree ./staff
```

```css:./app/assets/stylesheets/participant.css
*= require_tree ./participant
```




### 作成したcssファイルをアセットプリコンパイルの対象に加える

以下のように追加

```ruby:./config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( admin.css )
Rails.application.config.assets.precompile += %w( staff.css )
Rails.application.config.assets.precompile += %w( participant.css )
```



### それぞれのネームスペース毎にスタイルを適用させる

スタイルリンクタグを修正

```html+erb:./app/views/layouts/admin.html.erb
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
```

↓

```html+erb:./app/views/layouts/admin.html.erb
<%= stylesheet_link_tag    'admin', media: 'all', 'data-turbolinks-track': 'reload' %>
```

他もそれぞれ修正

./app/views/layouts/staff.html.erb
./app/views/layouts/participant.html.erb

### スタイルを適用してみる
今回は、以下のように実験してみました


```scss:./app/assets/stylesheets/admin/test_admin.scss
body {
  background: red;
}
```

```scss:.app/assets/stylesheets/staff/test_staff.scss
body {
  background: green;
}
```

```scss:./app/assets/stylesheets/participant/test_participant.scss
body {
  background: blue;
}
```

### ブラウザで確認

/admin/test_admin/new
![admin_asset.png](https://qiita-image-store.s3.amazonaws.com/0/54809/5f4c8376-c735-a5ef-198f-d5ba5a833715.png)

/staff/test_staff/new
![staff_asset.png](https://qiita-image-store.s3.amazonaws.com/0/54809/36723d86-47a9-c5ab-c9f1-43cb17e54bb2.png)

/participant/test_participant/new
![participant_asset.png](https://qiita-image-store.s3.amazonaws.com/0/54809/40ea40e9-1ba4-03cf-3b23-511d4f646c66.png)


サーバーを一度再起動せずに、アクセスすると以下のようなエラーが画面が表示されます。
その際は、サーバーを再起動してください。
![asset_error.png](https://qiita-image-store.s3.amazonaws.com/0/54809/f91405cb-e898-72cf-21a9-6f8af149e799.png)


### 共通のスタイルなど

全体の設定など、共通のスタイルを当てる場合は以下のようにしています。

```scss:./app/assets/stylesheets/public/test_public.scss
header {
  background: yellow;
}
```
を作り

```scss:./app/assets/stylesheets/admin.css
*= require_tree ./public
```
のようにそれぞれのcssを修正

/admin/test_admin/new
![admin_public.png](https://qiita-image-store.s3.amazonaws.com/0/54809/6ca8b25b-75cc-31d6-d59e-5c4ddad0914e.png)

/staff/test_staff/new
![staff_public.png](https://qiita-image-store.s3.amazonaws.com/0/54809/baed0b87-863c-e00c-ed11-4a190c4dbcde.png)

/participant/test_participant/new
![participant_public.png](https://qiita-image-store.s3.amazonaws.com/0/54809/4881e238-cef0-83be-0072-b244954c6d00.png)

## Jsファイルの振り分けを行う

### jsファイルの作成

application.jsとは別にadmin.jsを以下のように作成してください

```js:./app/assets/javascripts/admin.js
//= require rails-ujs
//= require turbolinks
//= require_tree ./admin
```

他もそれぞれjsファイルを作ります。

```js:./app/assets/javascripts/staff.js
//= require_tree ./staff
```

```js:./app/assets/javascripts/participant.js
//= require_tree ./participant
```


### 作成したjsファイルをアセットプリコンパイルの対象に加える

以下のように追加

```ruby:./config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.precompile += %w( staff.js staff.css )
Rails.application.config.assets.precompile += %w( participant.js participant.css )
```

### それぞれのネームスペース毎にJSを適用させる

JSインクルードタグを修正

```html+erb:./app/views/layouts/admin.html.erb
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
```

↓

```html+erb:./app/views/layouts/admin.html.erb
<%= javascript_include_tag 'admin', 'data-turbolinks-track': 'reload' %>
```

他もそれぞれ修正

./app/views/layouts/staff.html.erb
./app/views/layouts/participant.html.erb


### JSを適用してみる
今回は、以下のように実験してみました

```coffeescript:./app/assets/javascripts/admin/test_admin.coffee
alert 'admin'
```

```coffeescript:./app/assets/javascripts/staff/test_staff.coffee
alert 'staff'
```

```coffeescript:./app/assets/javascripts/participant/test_participant.coffee
alert 'participant'
```

### ブラウザで確認

/admin/test_admin/new
![admin_js.png](https://qiita-image-store.s3.amazonaws.com/0/54809/429229d3-a79b-1dc7-4c14-3d60565a954b.png)

/staff/test_staff/new
![staff_js.png](https://qiita-image-store.s3.amazonaws.com/0/54809/fb160ab9-c7eb-dbdd-f957-8fe8fe9209eb.png)

/participant/test_participant/new
![participant_js.png](https://qiita-image-store.s3.amazonaws.com/0/54809/c17bb7c5-d59e-26ca-5a99-84b05dd32eb6.png)

サーバーを一度再起動せずに、アクセスすると以下のようなエラーが画面が表示されます。
その際は、サーバーを再起動してください。
![asset_js_error.png](https://qiita-image-store.s3.amazonaws.com/0/54809/fa839877-099e-3876-fcd4-d621818bb86a.png)

## 終わりに
以上が、Rails(5)namespaceでディレクトリで分ける方法になります。
勉強不足で、このやり方が最適な方法か否かはわかりません。
もし、もっといい方法知ってる方いらっしゃいましたらぜひコメント等で教えてください。