第2回 Rails勉強会


第１回は[こちら](http://qiita.com/CyberMergina/items/068a8fde170f1c0daf0d)！

# Active Recordとは？
 
　Railsとデーターベースを繋ぐ仕組み（MVCでのモデルの部分の仕組み）のこと。
　※個人的な解釈なので、少し違ったりするかも。。。
　RailsではデータベースにはデフォルトSQLiteを使うようになっています。
　ですが、設定次第でMySQL,PostgreSQL,MongoDB,CouchDBなど他のデータベースが使用できます。
　今回は**MongoDB**を使います。

# MongoDBの準備
　環境の構築方法は[こちら](http://qiita.com/CyberMergina/items/402ca56cd3b9e318ce7a)

## データベースの操作をMongoDBのシェルから行う

　MongoDBを起動させている状態で、新しくシェルを立ち上げて `mongo` コマンドを打ちます。
　MongoDBのシェルが立ち上がるのでここでデータベースの操作を行います。
　抜けるときは `Ctrl + C` です。

```shell-session:shell
  $ mongo
  $ MongoDB shell version: 2.6.10
  $ connecting to: test
  $ >
```

### データベースを追加する

　`use [データベース名]` をシェルに打ちます。
 
　※これでデータベースの作成または選択が出来ます。作成したとしても、
　　コレクションを追加しない限りは保存されませんので注意してください。

```shell-session:shell
  $ > use mongo_project_development
  $ switched to db mongo_project_development
```

### コレクションを追加する

　`db.createCollection(コレクション名)` をシェルに打ちます。

```shell-session:shell
$ > db.createCollection('tasks')
```

### サンプルデータを追加する

`db.[コレクション名].insert(JSON形式のデータ)`  をシェルに打ちます。

```shell-session:shell
$ > db.tasks.insert({text: 'tasks1'})
$ WriteResult({ "nInserted" : 1 })
$ > db.tasks.insert({text: 'tasks2'})
$ WriteResult({ "nInserted" : 1 })
$ > db.tasks.insert({text: 'tasks3'})
$ WriteResult({ "nInserted" : 1 })
```

ここまででデータベースの準備は完了です。

### データの確認

- MongoDBのシェルで確認する

　`db.[コレクション名].find()` をシェルに打ちます。コレクションの全データが表示されます。
 
```shell-session:shell
db.tasks.find()
```

- GUIツールで確認する
反映されないようであればGUIツールの再起動をしてみてください。
GUIツールのインスコ方法は[こちら](http://tech.voyagegroup.com/archives/7720370.html)
仮想環境で作業していて、ホストPC側からGUIで確認したい場合は[こちら](http://qiita.com/CyberMergina/items/402ca56cd3b9e318ce7a)

# MongoDBを使ったプロジェクトを作成しましょう

- プロジェクト作成
`--skip-active-record`と`--skip-bundle`でデフォルトでSQLiteの設定をされないようにします。

```shell-session:shell
$ rails new mongoProject --skip-active-record --skip-bundle
```

- MongoDBに必要なgemの追記

```shell-session:shell
$ cd mongoProject
$ vi Gemfile
```

```text:mongoProject/Gemfile
# 追記(本当はバージョンを指定した方がいいです。)
gem 'mongoid'
# ついでにコメントアウト
# gem 'jbuilder', '~> 2.0'
```

- gemのインスコ

```shell-session:shell
$ bundle install
```

-  mongoidの設定ファイル作成

```shell-session:shell
# sampleProject/config/mongoid.yml という設定ファイルが作成される
$ rails g mongoid:config
```

- 設定ファイルの操作
databaseとhostsの項目を自分の環境に合わせて設定する。(基本的には変更の必要はないです。)
認証を書けている場合には、

```text:sampleProject/config/mongoid.yml
development:
  # Configure available database sessions. (required)
  sessions:
    # Defines the default session. (required)
    default:
      # Defines the name of the default database that Mongoid can connect to.
      # (required).
      database: mongo_project_development  # ここ
      # Provides the hosts the default session can connect to. Must be an array
      # of host:port pairs. (required)
      hosts:
        - localhost:27017 # ここ
```

- アプリケーション設定を編集
railsを起動するときにIPを指定しているので application.rb に以下を追記しましょう。
```rb:config/application.rb
module MongoProject
  class Application < Rails::Application
    config.web_console.whitelisted_ips = '192.168.33.1' # これを追記
```

# ページの用意

前回使用した `rails g controller` と、モデルの追加を行う `rails g model` を使用します。

```shell-session:shell
# rails g controller [コントローラ名(複数形)] [ページ名]
$ rails g controller tasks index
# rails g model [モデル名(単数形)] [フィールド名]
$ rails g model task text
```

ベースは出来たので `rails s -b [IPアドレス]` で起動してみてください。
問題なくRailsのスタートページが表示されましたら、次へ進みます。

# 前回のプロジェクトの模造品を作りましょう

対象となるのは以下のファイル達です。

- app/assets/stylesheets/tasks.scss
- app/views/tasks/index.html.erb
- config/routes.rb

このうち、 `app/controllers/tasks_controller.rb ` 以外は中身を書き換えてしまってください。

## 一覧表示

データベースに用意したリストを一覧に表示させてみます。

### コントローラの修正

```rb:app/controllers/tasks_controller.rb
  def index
    @taskList = Task.all
  end
```

`@taskList` というインスタンス変数に `Task.all` で取得した `tasks`コレクションのデータを全て渡しています。

### ビューの修正

```erb:app/views/tasks/index.html.erb
  <div id="taskListArea">
    <ul>
      <!-- (1) -->
      <% @taskList.each_with_index do | value, key | %>
        <!-- (2) -->
        <li><%= value.text %> [ <%= link_to "Remove", tasks_delete_path(key), :method => "delete" %> ] </li>
      <% end %>
    </ul>
  </div>
```

(1). `$taskList` というグローバル変数から `@taskList` というインスタンス変数で渡されるようになったので受け取り側も変更します。
(2). MongoDBにサンプルデータを投入したときに `{text: 'tasks1'}` というオブジェクトの形でデータを登録したと思います。
　`each_with_index`のループ内の `value` にはそのデータがオブジェクトの形のまま渡されています。
 　表示には `text` というキーの持っているデータを使うのでキーを指定してデータを表示しましょう。

## 登録処理

```rb:app/controllers/tasks_controller.rb

  def add
  # データを新規作成するときの形です。（モデル名.new()）
  # 引数に task_params と入っていますが、これは直下にある関数の事です。
  # 関数の戻り値がセットされるようになります。
    @task = Task.new(task_params)

    respond_to do |format| # 出力形式を指定してフォーマットを変更してくれる関数（特に必ず覚える必要はないです・・・）
    if @task.save # Task.newの返り値に save 関数を使用することで保存処理が行われる。
        format.html { redirect_to :tasks_index, notice: 'Task was successfully created.' }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :new }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

    # 登録する内容を精査するための関数。
    def task_params
      params.require(:tasks).permit(:text)
    end

```

```erb:app/views/tasks/index.html.erb
  <!-- (1) -->
  <%= form_for :tasks, :url => {:action => 'add'} do |f| %>
    <div id="taskAddArea">
      <!-- (2) -->
      <div id='taskInputArea'><%= f.text_field :text %></div>
      <div id='taskAddBtnArea'><%= button_to "ADD", :action => "add" %></div>
    </div>
  <% end %>
```

(1). formタグの書き方をこの形にすることで後々処理が楽になリます。実務ではこの形で書くことが多くなると思います。
(2). inputタグのテキストボックスの書き方を変えました。コチラも後々の処理が楽になります。

どちらもformの内容をpostさせるような場所ではこういった書き方をお勧めします。
第３回あたりの記事で書けるように頑張ります。。

# 削除処理（物理削除）

```rb:app/controllers/tasks_controller.rb
  def remove
    @task = Task.find(params[:id]) # ビューから渡される、データで保持している一意のIDを使用して削除対象のデータを取得しインスタンス変数へ格納
    @task.delete # 物理削除
    respond_to do |format|
      format.html { redirect_to :tasks_index, notice: 'Task was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
```


```erb:app/views/tasks/index.html.erb
  <ul>
    <% @taskList.each_with_index do | value, key | %>
      <!-- (1) -->
      <li><%= value.text %> [ <%= link_to "Remove", tasks_delete_path(value._id), :method => "delete" %> ] </li>
    <% end %>
  </ul>
```

(1).  `tasks_delete_path(key)` を `tasks_delete_path(value._id)` に変更し、コントローラ側にデータで保持している一意のIDを渡す。

第２回はここまでとなります！
（分かりにくいテキストになっているので少しずつブラッシュアップしていきます・・・；）
第３回は落ち着いたら書いていきます～^^

# 追記
scivolaさん、編集リクエストありがとうございます！！
非常に助かりました；