Ruby on Railsに手を出してみたのでそのメモ


最近ちょっと作りたいサービスがあって、サーバサイドとしてRuby on Railsをやってみようと思い立ち、入門してみました。
そもそもRuby自体ほとんど書いたことないので、細かいものをつらつらとメモしていきます。

## Railsとは

Railsにはいくつか大事な考え方があるようです。
ひとつは DRY（Don't Repeat Your self）で、同じことを繰り返すな、ということ。なので同じ記述が現れるところはどんどん共通化していく方針のようです。（そのための仕組みが多数用意されています）

そしてもっとも大事なものが「[設定より規約](https://ja.wikipedia.org/wiki/%E8%A8%AD%E5%AE%9A%E3%82%88%E3%82%8A%E8%A6%8F%E7%B4%84)」と呼ばれるソフトウェア設計パラダイムです。
端的に言うと、規約に基いてコードを書けば設定はいらない、ということです。

つまり、Rails側で規約を定めていて、その規約に則ってコードを書いている限り、設定を書く必要がなくなります。
なので、ルールに基いてモデルクラスを宣言するだけで基本的な処理（Create, Read, Update, Delete）などは自動的に行われます。


### MVCに基づく設計

![](http://image.itmedia.co.jp/ait/articles/1102/23/r13zu.png)
[MVCとRailsの基本構成を学ぼう](http://www.atmarkit.co.jp/ait/articles/1102/23/news109.html)から引用

後述しますが、モデルやコントローラのひな形を自動生成してくれる便利なコマンドがあります。
基本的な処理はそのコマンドから初めて、必要な箇所だけあとから編集、というのがおおまかな処理の流れになると思います。


### Model

`app/models` に配置されます。

Modelは `ActiveRecord::Base` クラスを継承したものになります。
基本的な `CRUD (Create, Read, Update, Delete)` の仕組みはベースクラスで定義されているため、特殊な処理がないモデルの場合は以下のように定義するだけで基本的な機能を使うことができます。

コメントで指摘もらいましたが、あくまでその処理を行うことが定義されている、という意味です。
なので実際にアプリケーションとして実行可能な状態にするにはコントローラなどとの連携が必要になります。


```ruby:Model
class Product < ActiveRecord::Base
end
```

#### インタラクティブな操作

以下のコマンドを使うと、ターミナルからインタラクティブにモデルデータの操作を行うことができます。

```console
$ rails console
Loading development environment (Rails 4.2.3)
2.2.3 :001 >
```

実行すると上記のようになるので、そこにRubyのコードを書いてモデルの生成を行うと、そのままDBに反映することができます。
（ちなみに `quit` で抜けることができます）

例)

```ruby
Product.create(title: "hoge")
```

#### Modelを作成する

モデルクラスのひな形とDBのマイグレーションファイルを作成するには以下のコマンドを実行します。

```console
$ rails g model ModelName fieldName1:string fieldName2:integer
```

ちなみに、デフォルトの型は `string` のため、`string` の型の場合は省略することができます。

また、いわゆる `has meny` な関係を作りたい場合は以下のようにします。

```console
$ rails g model Hoge title fuga:references
```

ここについては少し勘違いをしていました。
コメントを引用させてもらうと以下の意味のようです。

>fuga:references は，Fuga モデルに属すること（belongs_to）を含意しているだけです。Fuga モデルから見てこちらを has_many とは限りません。has_one かもしれない。

上記を実行するとHogeクラスには `belogns_to :fuga` が自動挿入されます。
ただ、fugaモデルにはその記述が自動挿入されないので、手で追記する必要があります。

```ruby
class Fuga < ActiveRecord::Base
	has_many :tasks # あるいは has_one
	# ...
end
```

##### Modelで使用される型


| 型 | 概要 |
|:----|:--------|
| string | 文字列 |
| text | 長い文字列 |
| integer | 整数 |
| float | 浮動小数点数 |
| decimal | 精度の高い小数 |
| datetime | 日時 |
| timestamp | タイムスタンプ |
| time | 時刻 |
| date | 日付 |
| binary | バイナリ |
| boolean | 真理値 |
| primary_key | 主キー |


#### Modelのカラムを更新する

[こちらの記事](http://www.rubylife.jp/rails/model/index7.html)を参考にしました。

Modelのカラムを更新するには、マイグレーションスクリプトを生成し、それを実行する必要があります。

例えば、`url` と `message` という新しいカラムを追加する場合は以下のようにします。

```console
$ rails g migration AddXXXToYYYY columnName:columnType (columnName:columnType ...)
```

ここで、`XXX` は追加するカラム名など任意の文字列です。（複数追加する場合などは明示できないため）
そして `YYY` は対象のテーブル名をスネークケースで指定します。

仮に `any_models` というテーブル名だったとしたら、 `AddParamsToAnyModels` という感じです。

そしてこれを実行するとRails側で適切にマイグレーションスクリプトを生成してくれます。
あとはこれを実行してあげればDBがマイグレーションされます。

```console
$ rake db:migrate
```

ちなみに `db/migrate/2015....rb` みたいな形でファイルが生成されますが、これを削除する場合は以下のようにします。

```console
$ rails destroy migration AddParamsToAnyModels
```

ファイルを直に消しても大丈夫かはやってないので分かりません・・。


#### Modelに関する規約

Railsのルール（規約）として、モデルは **大文字始まりの単数形** が定められています。



### Controller

`app/controllers` に配置されます。

ユーザからの操作を受け付けて、アプリケーションの動作を決定するコントローラです。

#### ルーティングを設定する

プロジェクトディレクトリの下に `config` ディレクトリがあります。
その中の `routes.rb` ファイルにルートをに関する設定をしてあげると自動的にそのルーティングを行う処理を実行してくれます。

```ruby
Rails.application.routes.draw do
	resources :projects
	
	# 以下略
end
```

##### rootを設定する

サイトトップにアクセスしたときなどに、どこを表示して欲しいかをコントローラとアクションの単位で指定しておくことができます。

例)

```ruby
root 'projects#index'
```

上記のようにすると、トップに来た場合に `projects` の `index` アクションが実行されます。


##### URLの階層を定義する

以下のようにすることで、あるモデル以下に紐付いた他モデルのデータ（has many的な）を表示、というようなURLのルーティングを実現することができます。
（いわゆるhas manyの関係にあるデータの表示とか）

```ruby
resources :projects do
	resources :tasks, only: [:create, :destroy]
end
```

こうすることで、とあるプロジェクトに紐付いたタスク一覧を表示するURLを設定することができます。

##### 特定URLをアクションに結びつける

このURLにアクセスしたらこのアクションを実行したい、という場合は以下のようにすることで設定することができます。

```ruby
post '/projects/:project_id/tasks/:id/toggle' => 'tasks#toggle'
```

`tasks` はコントローラです。そのコントローラの `toggle` メソッド（アクション）を実行する設定です。


#### Controllerのルーティングを確認する

ルーティングの設定ができたら `rake routes` コマンドでルーティングを確認することができます。

```console
$ rake routes
       Prefix Verb   URI Pattern                                      Controller#Action
project_tasks POST   /projects/:project_id/tasks(.:format)            tasks#create
 project_task DELETE /projects/:project_id/tasks/:id(.:format)        tasks#destroy
     projects GET    /projects(.:format)                              projects#index
              POST   /projects(.:format)                              projects#create
  new_project GET    /projects/new(.:format)                          projects#new
 edit_project GET    /projects/:id/edit(.:format)                     projects#edit
      project GET    /projects/:id(.:format)                          projects#show
              PATCH  /projects/:id(.:format)                          projects#update
              PUT    /projects/:id(.:format)                          projects#update
              DELETE /projects/:id(.:format)                          projects#destroy
              POST   /projects/:project_id/tasks/:id/toggle(.:format) tasks#toggle
         root GET    /                                                projects#index
```

#### before_action, after_action

モデルの取得など、各アクションの中で共通に処理する部分があるかと思います。
その際に、同じことを書くのはDRYに反するので、`before_action` や `after_action` に処理をまとめることで共通化することができます。
具体的には以下のようにします。

```ruby:controller
class ProjectsController < ApplicationController
	before_action :anyMethod, only: [:show, :edit]
	
	private
		def anyMethod
			# do common action
		end
end
```

ちなみにこの `before_action` という記述はRubyの機能で、クラス・メソッドなどを指定するとそれがクラス宣言時に実行されるようになります。
※ コメントで指摘をもらったので補足しておきます。`before_action` というメソッド自体はRails側の機能です。ただ、クラス宣言時に実行される、という点がRubyの機能という意味です。


#### Controllerに関する規約

モデルを操作するコントローラを作成する場合は同様に、モデル名の複数形で作成する必要があります。上記の例で言えば `Projects`。
さらに、上記のルーティングで示されている `Controller#Action` の項目が、コントローラにどのメソッドを実装したらどのアクションが実行されるかを表しています。
例えば、`index` メソッドを実装すれば `/projects(.:format)` にアクセスされたときにそれが実行されます。


### View

`app/views` に配置されます。

HTMLをレンダリングし表示するビュー。
ちなみに `ERB（Embed RuByの略）` を利用してHTMLを構築します。

```erb
<% if (hoge) %>
	ここにHTML
<% end %>

<%= hoge.name %>
```

`<% ~ %>` と `<%= ~ %>` という記述方法がある。
前者はRubyを実行するだけで返り値は無視されますが、後者は戻り値がそのままHTMLとして出力される点が異なります。

#### パーシャルを使う

DRY（Don't repeat your self）の精神で、同じことを記述することを避けるのがRails風です。
ということで、Viewの中で同じ記述が現れる箇所がある場合は、「パーシャル」という機能を使ってまとめておくと便利です。

パーシャルの使い方にもルールがあり、以下のように記述します。

```erb
<%= render 'hoge' %>
```

上記は `erb` ファイルの一部です。上記のように `render` メソッドを使ってパーシャルを呼び出します。
パーシャル自体は、Viewsの中に、renderの引数に渡された文字列にアンダースコアを付けたファイル（上記の例では `_hoge.erb`）を作成し、そこに共通項目を書きます。
あとはRailsが規約に則って該当のパーシャルのその位置に読み込んでくれます。


#### Viewに関する規約

Viewに関する規約は、コントローラのアクション名と同名のファイル名にする、という点です。
（例えば `index` アクションなら `index.html.erb` ファイル）

#### 共通テンプレート

Viewはまた、共通テンプレートを持つことができます。HTML内のhead要素などサイト内で共通にしておきたいものはたくさんあると思います。
それらについては `app/views/layouts` ディレクトリ内に配置されます。

また、各Viewに記述された内容はテンプレート内の `<%= yield %>` に展開されるようになっています。


## プロジェクトの作成

以下の `rails` コマンドでさくっと新規プロジェクトが生成できます。

```console
$ rails new hoge
```

### データ（モデル）の作成

モデルの作成には `bundle exec rails generate scaffold` を使います。

```console
$ rails generate scaffold hoge name:string fuga:string
```

ちなみに、`generate` は `g` のみでも実行可能です。

```console
$ rails g scaffold hoge name:string fuga:string
```

また、DBのマイグレーションファイルも自動生成されるため、以下のようにすることでDBをマイグレーションすることができます。

```console
$ rake db:migrate
```

### 作成したアプリケーションの動きをブラウザで確認する

```console
$ rails server
```

`s` だけでも起動できます。

```console
$ rails s
```


### bundle exec

いくつかのコマンドで `bundle exec` というのが使われていますが、これは、プロジェクト内の `vendeor/bundle` 内に保存されている `gem` を使うためのコマンドのようです。


-------------------------------------------

## Rails 4からの便利機能

`http://localhost:3000/rails/info/routes` でルートを確認することができます。
POSTやGETの種類、引数としてどんなパラメータが必要かなどが一覧されるので便利。


-------------------------------------------

## 覚えておきたいメモ

レスポンスを `JSON` で返します。

controllerで出し分けができるみたい。
具体的には以下。

```ruby:json
class AnyController < ApplicationController
	def index
		@products = Product.all
		
		respond_to {|format|
			format.html # => 通常のアクセス
			format.json { render json: @products } # URLが `.json` でのアクセス
		}
	end
end
```

上記のように、アクション処理の中で `respond_to` メソッドを使って、フォーマットに応じて処理を分けてやると実現できます。


**Rubyについてのメモ** は[別記事](http://qiita.com/edo_m18/items/1cf5a149a0b8d624b273)に移動しました。

### JSONを返すAPIで

スタブ環境みたいなものを作ろうと思って、モデルを2つ用意して、それをネストしてJSONとして返す、みたいなことをやろうとして意外とハマったのでメモ。

以下のようなモデルがあったとして。

```ruby
class HogeModel < ActiveRecord::Base
    has_one :fuga_model
end
```

```ruby
class FugaModel < ActiveRecord::Base
    belongs_to :hoge_model
end
```

こんな感じでコントローラを書く。

```ruby
class HogeModelsController < ApplicationController
    def index
        @hoge_models = HogeModel.all
        @fuga_models = FugaModel.all

        render :json => @hoge_models, :methods => :fuga_model
    end
end
```

まだRubyからして怪しいけど、とりあえずこれで目的のような形になった。

## 参考記事

- [簡単インストールから始める初心者のためのRuby on Railsチュートリアル](http://www.atmarkit.co.jp/ait/articles/1402/28/news047.html)