Rails で namespace を適用する方法 ( scaffold 編 )

## やりたい事
* 管理画面用に scaffold で作成した CRUD ( Create, Read, Update, Delete ) へ namespace を適用し、/admin/ のような URL でアクセスしたい。

* controller , view , helper や、assets 配下の javascripts , stylesheet , image を namespace でディレクトリ分けし、見通しを良くしたい。
( app/controllers/admin/\*\*\*_controller.rb , app/assets/javascripts/admin/\*\*\*.js ... )

* namespace を利用し、コントローラとビューはわけても、モデルはわけたくない。


## 前提

|       | バージョン |
|:------|:---------|
| Ruby  | 2.1.1    |
| Rails | 4.2.0    |

stores という店舗情報を格納するテーブルを例に説明。

| 列名 | データ型 | 概要 |
|:--|:--|:--|
| name | string | 店舗名 |
| address | string | 所在地 |
| access | text | アクセス |


## 1. scaffold で CRUD 作成

`$ rails generate scaffold store name:string address:string access:text`
`$ rake db:migrate`


## 2. ルーティング修正

admin という namespace を適用。

```config/routes.rb
resources :stores

↓以下のように修正

namespace :admin do
  resources :stores
end
```


## 3. namespace でディレクトリを作成し、生成されたファイルを移動

* app/assets/javascripts/admin/ ディレクトリを作成し、stores.coffee をこの中へ移動。

* app/assets/stylesheets/admin/  ディレクトリを作成し、stores.scss をこの中へ移動。

* app/assets/images/admin/ ディレクトリを作成。

* app/controllers/admin/ ディレクトリを作成し、stores_controller.rb をこの中へ移動。

* app/helpers/admin/ ディレクトリを作成し、stores_heler.rb のこの中へ移動。

* app/views/admin/ ディレクトリを作成し、stores ディレクトリをこの中へ移動。

* test/controllers/admin/ ディレクトリを作成し、stores_controller_test.rb をこの中へ移動。


## 4. 各ソースの修正

* form_for ヘルパー、link_to ヘルパー、redirect_to メソッドへ渡す値を namespace を含めた配列に変更する。

* namespace を適用したことで、ルーティングの url ヘルパーが変更されている ( stores_path -> admin_stores_path 等 ) ので、修正する。

---

### コントローラのクラス名、コントローラテストのクラス名、ヘルパーのモジュール名へ namespace を適用。

```app/controllers/admin/stores_controller.rb
class StoresController < ApplicationController

↓以下のように修正

class Admin::StoresController < ApplicationController
```

```test/controllers/admin/stores_controller_test.rb
class StoresController < ApplicationController

↓以下のように修正

class Admin::StoresController < ApplicationController
```

```app/helpers/admin/stores_helper.rb
module StoresHelper

↓以下のように修正

module Admin::StoresHelper
```

---

### 一覧表示機能のソース修正

```app/views/admin/stores/index.html.erb
<td><%= link_to 'Show', store %></td>
<td><%= link_to 'Edit', edit_store_path(store) %></td>
<td><%= link_to 'Destroy', store, method: :delete, data: { confirm: 'Are you sure?' } %></td>

↓以下のように修正

<td><%= link_to 'Show', [:admin, store] %></td>
<td><%= link_to 'Edit', edit_admin_store_path(store) %></td>
<td><%= link_to 'Destroy', [:admin, store], method: :delete, data: { confirm: 'Are you sure?' } %></td>


<%= link_to 'New Store', new_store_path %>

↓以下のように修正

<%= link_to 'New Store', new_admin_store_path %>
```

```app/views/admin/stores/index.json.jbuilder
json.url store_url(store, format: :json)

↓以下のように修正

json.url admin_store_url(store, format: :json)
```

---

### 新規登録機能のソース修正

```app/views/admin/stores/_form.html.erb
<%= form_for(@store) do |f| %>

↓以下のように修正

<%= form_for([:admin, @store]) do |f| %>
```

```app/views/admin/stores/new.html.erb
<%= link_to 'Back', stores_path %>

↓以下のように修正

<%= link_to 'Back', admin_stores_path %>
```

```app/controllers/admin/stores_controller.rb
if @store.save
  format.html { redirect_to @store, notice: 'Store was successfully created.' }
  format.json { render :show, status: :created, location: @store }

↓以下のように修正

if @store.save
  format.html { redirect_to [:admin, @store], notice: 'Store was successfully created.' }
  format.json { render :show, status: :created, location: [:admin, @store] }
```

---

### 詳細表示機能のソース修正

```app/views/admin/stores/show.html.erb
<%= link_to 'Edit', edit_store_path(@store) %> |
<%= link_to 'Back', stores_path %>

↓以下のように修正

<%= link_to 'Edit', edit_admin_store_path(@store) %> |
<%= link_to 'Back', admin_stores_path %>
```

---

### 編集機能のソース修正

```app/views/admin/stores/edit.html.erb
<%= link_to 'Show', @store %> |
<%= link_to 'Back', stores_path %>

↓以下のように修正

<%= link_to 'Show', [:admin, @store] %> |
<%= link_to 'Back', admin_stores_path %>
```

```app/controllers/admin/stores_controller.rb
if @store.update(store_params)
  format.html { redirect_to @store, notice: 'Store was successfully updated.' }
  format.json { render :show, status: :ok, location: @store }

↓以下のように修正

if @store.update(store_params)
        format.html { redirect_to [:admin, @store], notice: 'Store was successfully updated.' }
        format.json { render :show, status: :ok, location: [:admin, @store] }
```

---

### 削除機能のソース修正

```app/controllers/admin/stores_controller.rb
format.html { redirect_to stores_url, notice: 'Store was successfully destroyed.' }

↓以下のように修正

format.html { redirect_to admin_stores_url, notice: 'Store was successfully destroyed.' }
```


### コントローラテストのソース修正

```test/controllers/admin/stores_controller_test.rb

# should create store テストを修正

assert_redirected_to store_path(assigns(:store))

↓以下のように修正

assert_redirected_to admin_store_path(assigns(:store))


# should update store テストを修正

assert_redirected_to store_path(assigns(:store))

↓以下のように修正

assert_redirected_to admin_store_path(assigns(:store))


# should destroy store テストを修正

assert_redirected_to stores_path

↓以下のように修正

assert_redirected_to admin_stores_path
```


## 5. テスト

`$ rake db:migrate`
`$ rake db:test:load`
`$ rake test:controllers TEST="test/controllers/admin/stores_controller_test.rb"`

エラーが無ければ OK 。

`$ rake db:test:purge`

---

お疲れ様でした。