初めてのRuby on Rails。Twitterみたいなサイトを作成しよう

- [小学生でもわかるRuby on Rails入門](http://openbook4.me/projects/92)に従って、Twitterみたいなサイトを作成してみます。

## 1 Railsとは
- Webアプリケーションを開発するために設計されたものをWebアプリフレームワークと言います。
- フレームワーク自体はプログラミング言語ではありません。フレームワークはある特定のことに特化した機能を集めたものです。
- 最も先進的で安定しており、豊富なRubyGemsライブラリがあることで他のフレームワークに比べプロトタイプを作るスピードを早めることが可能

## 2 Railsの導入
- RubyGemsを使ってインストール。

~~~sh
sudo gem install rails
~~~ 

- **Xcodeまたはコマンドラインツールに問題**がある場合は、下記コマンドで再インストールする。

~~~sh
xcode-select --install
~~~

## 3 Railsアプリの新規作成
- Twitterのようなアプリを soushi-twitter という名前作ることにします。
- 下記コマンドを打つと、自動でRailsアプリのテンプレートが生成されます。

~~~sh
rails new soushi-twitter
cd ~/soushi-twitter
~~~

- treeコマンドで自動生成されたファイルを確認します。

~~~sh
tree ~/soushi-twitter
├── Gemfile
├── Gemfile.lock
├── README.rdoc
├── Rakefile
├── app
├── bin
├── config
├── config.ru
├── db
├── lib
├── log
├── public
├── test
├── tmp
└── vendor
~~~

## 4 Railsアプリをカスタマイズする

### 4.1 モデルー・ビュー・コントローラ(MVCモデル)
- RailsにおけるモデルはPush-MVCと呼ばれるものです。
- これは、ModelとView、両者を知っているのは、Controllerしかいません。よってControllerにがんばってもらおう、という戦略です。
- ViewはControllerがトリガになって更新されるため、受け身です。このことから、このViewのことをPassive Viewと呼んだりします。
- 参考 [MVC、本当にわかってますか？](http://qiita.com/tshinsay/items/5b1724baf32b8b5113c2)

### 4.2 ビューおよびコントローラーの作成
- コマンド1つで作成できます。
- このindexというのは、ユーザーの一覧ページ。showというのは、ユーザーのプロフィールページです。
- indexやshowは自分で==自由に名前をつけることが可能==ですが、あとで説明するように==index==、==show==というようにつけるのが==良し==とされています。
- また、==コントローラー名は==usersというように==複数形==にするのがよしとされています。
- こういう暗黙の約束事のようなものをRailsの規約と言います。 Railsはその名の通りレールに沿って作ればカンタンに作れる、という意味なので、出来る限りRailsが敷いたレールの上を走りましょう。

~~~sh
rails g controller users index show
~~~

- 次のようなファイルが自動生成されます。

~~~
app/controllers/users_controller.rb
app/views/users/index.html.erb
app/views/users/show.html.erb
~~~

### 4.3 サーバーの起動
- 実は、ここまででもうWebページが完成しています。

~~~sh
rails s
~~~

- `rails s`コマンドでサーバーを起動し、Webブラウザで`http://0.0.0.0:3000/users/index`にアクセスしてみます。

![初めてのRailsページ](https://qiita-image-store.s3.amazonaws.com/0/9023/005af2c8-5e47-6218-18b4-bb392c82d139.png)

### 4.4 ビューのカスタマイズ(1)
- `app/views/users/show.html.erb`を次のように編集します。

- app/views/users/show.html.erb

~~~html
<h1>Soushi Yamamoto</h1>
<p>soushiy</p>
<ul>
    <li>Location : Tokyo</li>
    <li>About	: Hello</li>
</ul>
~~~

![rails2.png](https://qiita-image-store.s3.amazonaws.com/0/9023/406a08c1-7097-e06a-5590-6da12310d1c1.png)


- Webブラウザで`http://0.0.0.0:3000/users/show`にアクセスします。

![rails3.png](https://qiita-image-store.s3.amazonaws.com/0/9023/67c56e4c-e117-c337-e7a1-4565e8137835.png)

### 4.5 ビューのカスタマイズ(2)
- 再度、`app/views/users/show.html.erb`を次のように編集します。
- app/views/users/show.html.erb

~~~html
<h1><%= @user[:name] %></h1>
<p><%= @user[:username] %></p>
<ul>
    <li>Location : <%= @user[:location] %></li>
    <li>About	: <%= @user[:about] %></li>
</ul>
~~~

- 再度、Webブラウザで`http://0.0.0.0:3000/users/show`にアクセスします。
- エラーが発生しています。

![rails4.png](https://qiita-image-store.s3.amazonaws.com/0/9023/7dccfad6-0f5f-bef8-ef77-8decee585418.png)

- `undefined method '[]' for nil:NilClass`というエラーは、@userから情報を引っ張ろうとしているけど、@userに情報が入っていないということで起こっています。
- そこで、コントローラーで@userに情報を埋め込みます。

### 4.6 コントローラーのカスタマイズ
- コントローラーを編集して、@userに情報を埋め込みます。
- `app/controllers/users_controller.rb`を次のように変更します。

~~~ruby
class UsersController < ApplicationController
	def index
	end

	def show
		@user = Hash.new
		@user[:name] = 'Soushi Yamamoto'
		@user[:username] = 'soushiy'
		@user[:location] = 'Tokyo, Japan'
		@user[:about] = 'Hello.'
	end
end
~~~

- 正しく表示できました。

![rails6.png](https://qiita-image-store.s3.amazonaws.com/0/9023/d2d5b7fb-fef8-bb49-699f-149b1254d32a.png)

## 5 ルーチングの設定
### 5.1 ルーチングの必要性
- `http://0.0.0.0:3000/users/show`にアクセスすると、すべて同じ人のプロフィールになっています。
- これを`http://0.0.0.0:3000/users/show/soushiy`にアクセスすると、`soushiy`のプロフィールが表示され、
- `http://0.0.0.0:3000/users/show/tanaka`
にアクセスすると、`tanaka`のプロフィールがそれぞれ表示されるようにするために、ルーチングという仕組みを使います。
### 5.2 ルーチングの役割
- ルーチングはユーザーがアクセスしたURLをもとに何を表示するかをすべて振り分けています。
- すなわち、ルーチングの役割は、ユーザーがSoushi Yamamotoを表示しろというURLにアクセスしたら、その情報を表示するようにし、Taro Tanakaを表示しろというURLにアクセスしたら、その情報を表示するようにする、いわば「URLの仕分け」のようなことをしています。
- したがって、実はURLにアクセスした時に最初に通るところがルーチングになるのです。
- ページが表示されるまでの流れは以下のとおり。

1. `ユーザーがURLにアクセス`
2. `ルーチングが仕分け`
3. `コントローラーが値を入れる`
4. `ビューがコントローラーから渡された値を表示`

### 5.3 ルーチングのカスタマイズ
- `http://0.0.0.0:3000/users/show/soushiy`で、プロフィールページを表示したいので、`config/routes.rb`を下記のように編集します。

- config/routes.rb

~~~ruby
Rails.application.routes.draw do
  get 'users/index'
  get 'users/show'
  get 'users/show/:username' => 'users#show'
end
~~~

- WEBブラウザで`http://0.0.0.0:3000/users/show/soushiy`にアクセスします。

![rails7.png](https://qiita-image-store.s3.amazonaws.com/0/9023/93c64ce9-887d-73b3-6bd6-6ffd589299b6.png)

## 6 ルーチングからコントローラーへ値を渡す
- ルーチングの値は`params[:username]`で取得可能。
- これは、先ほど、ルーチングのファイル`config/routes.rb`に`get "users/show/:username" => "users#show"`と記述したからである。

- コントローラーの動作を、ルーチングによって変更するようにします。
- `app/controllers/users_controller.rb`を下記のように変更します。

~~~ruby
class UsersController < ApplicationController
	def index
	end

	def show
		@user = Hash.new
		if params[:username] == 'soushiy'
			@user[:name] = 'Soushi Yamamoto'
			@user[:username] = 'soushiy'
			@user[:location] = 'Tokyo, Japan'
			@user[:about] = 'Hello.'
		elsif params[:username] == 'tarot'
			@user[:name] = 'Taro Tanaka'
			@user[:username] = 'tarot'
			@user[:location] = 'Yamaguchi, Japan'
			@user[:about] = 'I'm Taro.'
		end
	end
end
~~~

- WEBブラウザで`http://0.0.0.0:3000/users/show/soushiy`と`http://0.0.0.0:3000/users/show/tarot`を開きます。

![rails7.png](https://qiita-image-store.s3.amazonaws.com/0/9023/93c64ce9-887d-73b3-6bd6-6ffd589299b6.png)

![rails8.png](https://qiita-image-store.s3.amazonaws.com/0/9023/1dc080d7-ea6b-2c25-aec3-a9d256469d35.png)

## 7. モデルの作成
- Railsにおけるモデルとは、mysqlやHBase(大規模キーバリューストア)等を指す。
- スキーマを直接定義するのではなく、マイグレーションを書く。

### 7.3.1 データベースの新規作成
- db/development.sqlite3 が作成されます。
- この時点では何もないまっさらなもの(スキーマやマイグレーションファイルも無い)。

~~~sh
rake db:create
~~~

### 7.3.2 モデルの作成
- モデルはusersではなく、userという単数形であることに注意しましょう。これもRailsの敷いたレールの一つです。


|**カラム名**|**型**|**意味**|
|----|----|----|
|name|string|表示名|
|username|string|ユーザー名|
|location|string|居住地|
|about|text|自己紹介|

~~~sh
rails g model user name:string username:string location:string about:text
~~~

- 下記は、マイグレーションの型とMySQL、Rubyの型の対応表です。

|**マイグレーションの型**|**MySQLの型**|**Rubyの型**|
|----|----|----|----|
|integer|int(11)|Fixnum|
|decimal|decimal(10,0)|BigDecimal|
|float|float|Float|
|string|varchar(255)|String|
|text|text|String|
|binary|blob|String|
|date|date|Date|
|datetime|datetime|Time|
|timestamp|datetime|Time|
|time|time|Time|
|boolean|tinyint(1)|TrueClass/FalseClass|

- 次のようなファイルが生成されます。
- user.rb･･･モデルファイル
- {日付}_create_users.rb･･･マイグレーションファイル

~~~
app/models/user.rb
db/migrate/20150825110207_create_users.rb
~~~

~~~ruby
cat db/migrate/20150825110207_create_users.rb 
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :username
      t.string :location
      t.text :about

      t.timestamps null: false
    end
  end
end
~~~

### 7.3.3 マイグレーションファイルを用いてデータベースにスキーマを適用
- 下記コマンドで、実際にスキーマが適用されたデータベースとなります。

~~~sh
rake db:migrate
~~~

## 8 データベースにデータを入れる
- ==初期データを入れるためのファイル==`db/seeds.rb`を、下記のように変更します。

~~~ruby
@user = User.new
@user.name = 'Soushi Yamamoto'
@user.username = 'soushiy'
@user.location = 'Tokyo, Japan'
@user.about = 'Hello, I am Soushi.'
@user.save

@user = User.new
@user.name = 'Taro Tanaka'
@user.username = 'tarot'
@user.location = 'Yamaguchi, Japan'
@user.about = 'Hi. I am Taro.'
@user.save
~~~

- 次のコマンドでデータベースにデータを追加します。

~~~sh
rake db:seed
~~~

## 9 データベースのデータを表示する
- コントローラー`app/controllers/users_controller.rb`を次のように変更します。
- 今回は`User.find_by(:username => params[:username])`となっていますが、`User.find_by(:name => 'Soushi Yamamoto')`や、`User.find_by(:id => 1)`という検索も可能です。
- idで探す場合は、単純に`User.find(1)`として、idが1のユーザーを取得することもできます。

~~~ruby
class UsersController < ApplicationController
	def index
	end

	def show
		@user = User.find_by(:username => params[:username])
	end
end
~~~

- WEBブラウザでそれぞれのページにアクセスします。

![rails9.png](https://qiita-image-store.s3.amazonaws.com/0/9023/45c3065d-8a01-f2b6-518b-0d4e6e06f62a.png)

![rails10.png](https://qiita-image-store.s3.amazonaws.com/0/9023/118df4a9-1b90-5ec6-04a1-00e917b5bc5f.png)

## 10 ツイートを保存するためのビュー・コントローラー・モデルを作成する

- ビューとコントローラーの作成

|**URL**|**意味**|
|----|----|
|index|タイムラインを表示する|
|show||
|new|新しいツイートを入力する画面|

~~~sh
rails g controller tweets index show new
~~~

- モデルの作成

|**カラム名**|**型**|**意味**|
|----|----|----|
|title|string|タイトル|
|content|text|内容|

~~~sh
rails g model tweet title:string content:text
rake db:migrate
~~~

## 11 ツイートを入力するためのフォームを作る
- 現在、`http://0.0.0.0:3000/tweets/new`の画面は、次のようになっています。

![rails11.png](https://qiita-image-store.s3.amazonaws.com/0/9023/c1baab45-1132-c94c-7204-855954f131a1.png)

### 11.1 ビューを修正する
- 新規ツイートを作成するための画面`app/views/tweets/new.html.erb`を、次のように変更します。
- このようなものを==ヘルパー==と言います。 この例の場合は、フォームヘルパーと呼ばれるものです。


~~~ruby
<%= form_for Tweet.new do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.label :content %>
  <%= f.text_area :content %>
  <%= f.submit %>
<% end %>
~~~

- views/tweetsフォルダが作成されています。

![rails12.png](https://qiita-image-store.s3.amazonaws.com/0/9023/165cdca0-7631-88ab-c578-781cf8b9a162.png)


### 11.2 NoMethodError in Tweets#newエラーに対処する
- ビューを修正した後、再度`http://0.0.0.0:3000/tweets/new`にアクセスすると、エラーが発生しています。

![uploading rails13.png...]()


- エラー内容は、==フォームの送信先が存在しない==というものです。

~~~
undefined method `tweets_path' for #<#<Class:0x007fe02b2a1918>:0x007fe02b2f8308>
~~~

- そこで、ルーチングの設定を書き換えて、送信先を定義してあげます。
- `config/routes.rb`を次のように書き換えます。
- ツイートのフォームを入力して、送信ボタンを押したら、tweetsコントローラーのcreate関数を呼びなさい、という意味です。==(create関数は未定義なので後で作成します。)==

~~~ruby
Rails.application.routes.draw do
  get 'tweets/index'
  get 'tweets/show'
  get 'tweets/new'
  post 'tweets' => 'tweets#create'

  get 'users/index'
  get 'users/show/:username' => 'users#show'
end
~~~

- 再度、`http://0.0.0.0:3000/tweets/new`にアクセスします。

![rails13.png](https://qiita-image-store.s3.amazonaws.com/0/9023/0e98d54a-8424-128b-a4dc-eae10999adab.png)

- ツイートを送信します。(失敗します。)

![rails15.png](https://qiita-image-store.s3.amazonaws.com/0/9023/43a56251-59f8-d3f8-4d6c-1408e78bda57.png)

- tweetsコントローラーに、create関数を追加します。
- `app/controllers/tweets_controller.rb`を次のように変更します。

~~~ruby
class TweetsController < ApplicationController
  def index
  end

  def show
  end

  def new
  end

  def create
  end
end
~~~

- create関数は追加できましたが、何も処理していません。
- 先ほどユーザー名の取得の際に、`params[:username]`としたのと同様に、`params[:tweet][:title]`でツイートのタイトルを取得します。

- 以下の様な形で、パラメータが飛んできます。

~~~ruby
params = { :tweet => { :title => "This is first tweet title", :content => "I am making how to make twitter app." } }
~~~

- そこで、`app/controllers/tweets_controller.rb`を次のように変更します。
- `params[:tweet][:title]`でタイトルの取得
- `params[:tweet][:content]`で内容の取得

~~~ruby
class TweetsController < ApplicationController
	def index
	end

	def show
	end

	def new
	end

	def create
		@tweet = Tweet.new
		@tweet.title = params[:tweet][:title]
		@tweet.content = params[:tweet][:content]
		@tweet.save
	end
end
~~~

- ここまでで、ツイートの内容は正しく保存されるようになりました。しかし、再度ツイートボタンを押して投稿しようとすると、下記の画面になります。

![rails16.png](https://qiita-image-store.s3.amazonaws.com/0/9023/44827a1c-d7de-4729-16df-4904500de024.png)

- これは、==create関数に対応するビューが存在しないため発生するエラーです。==
- createのビューは必要ないので、もしもデータを保存し終わったらツイートの一覧にリダイレクトさせるようにしましょう。
- `app/controllers/tweets_controller.rb`を次のように変更します。

~~~ruby
class TweetsController < ApplicationController
	def index
	end

	def show
	end

	def new
	end

	def create
		@tweet = Tweet.new
		@tweet.title = params[:tweet][:title]
		@tweet.content = params[:tweet][:content]
		@tweet.save
		redirect_to '/tweets/index'
	end
end
~~~

## 12 ツイートの一覧表示
- ツイートの一覧表示は`tweets#index`を変更すればよいのでした。
- 対応するコントローラー`app/controllers/tweets_controller.rb`を次のように編集します。
- `@tweets = Tweet.all`は、データベースからすべてのデータを取ってくるコマンドです。

~~~ruby
class TweetsController < ApplicationController
	def index
		@tweets = Tweet.all
	end

	def show
	end

	def new
	end

	def create
		@tweet = Tweet.new
		@tweet.title = params[:tweet][:title]
		@tweet.content = params[:tweet][:content]
		@tweet.save
		redirect_to '/tweets/index'
	end
end
~~~

- 次に、一覧表示のためのビューを変更します。
- ここで、Rubyのforループのおさらいです。
- 次のようにすると、0〜10までを足した数が表示されます。

~~~ruby
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sum = 0
numbers.each do |number|
  sum += number
end

puts sum
~~~

- このfor文を用いて、`app/views/tweets/index.html.erb`を次のように編集します。
- `<%`と`<%=`の違いに注意します。==イコールの無いものは、HTMLとして表示する必要のないもの==という意味です。

~~~ruby
<% @tweets.each do |tweet| %>
  <h1><%= tweet.title %></h1>
  <p><%= tweet.content %></p>
<% end %>
~~~

- 最後に、`http://0.0.0.0:3000/tweets/index`にアクセスします。

![rails17.png](https://qiita-image-store.s3.amazonaws.com/0/9023/7864dc88-556a-9483-21ad-271acbb9b274.png)

---

# この次のステップは？
ここまで学んできて、ある程度Railsの仕組みが理解できたでしょうか？
他にもまだまだやりたいことはたくさんあると思います。

画像をアップロードするためには、どうしたらいいの？
ユーザーのログインをして、ユーザーごとにツイートを表示したい。
実際のTwitterと連動して、ここでつぶやいたことをTwitterにも表示させたい。
などなど。

ここから先は、無限です。

Mitakalabコミュニティで学ぶもよし、本で独学するもよし、Google先生にきくもよし。

自分だけのアプリを作るべくがんばってください。

参考までに、この次のステップで有用なものを挙げておきます。

- [モデルを変更する](http://www.rubylife.jp/rails/model/index7.html)

- [Railscasts](http://railscasts.com/) : Railsの応用例がたくさん載っているサイトです。（英語・日本語）
- [Cumiki](http://cumiki.com/learn/rails) : Railsにかぎらず、Railsの応用例をどうやって付け加えるかを、レゴを組み立てるような手順で学ぶことができます。（日本語）
- [ドットインストール](http://dotinstall.com/lessons/basic_rails) : Railsにかぎらず、基本的な点を動画を使ってわかりやすく解説されています。（日本語）
- [Ruby Toolbox](http://ruby-toolbox.com/) : RailsにGemを追加して機能を付け加えたいときに、どんなGemがあるのかをカテゴリーごとに見ることができます。（英語）

# 参考文献
- [小学生でもわかるRuby on Rails入門](http://openbook4.me/projects/92/sections/488)