Railsことはじめ

とても秀逸なチュートリアル[Ruby on Rails Tutorial by Michael Hartl](http://ruby.railstutorial.org/ruby-on-rails-tutorial-book)の[日本語訳](http://railstutorial-ja.herokuapp.com/book/ruby-on-rails-tutorial?version=4.0)を体験してメモ。

# 環境
|OS|OS X (10.9)|
|:--|:--|
|Ruby|2.0.0|
|Rails|4.0.1|


# 前準備
RVMでRubyをインストール。（gemsetはプロジェクトごとに分けたい）

## RVM
RVMをインストール。

```
$ curl -L https://get.rvm.io | bash -s
$ rvm get stable
```

## Ruby
Rubyをインストール。

```
$ rvm requirements
$ rvm install 2.0.0 --with-openssl-dir=$HOME/.rvm/usr
```

## Gem
gemsetを作成。

```
$ rvm use 2.0.0@project_name_rails_4_0 --create
```

gemのドキュメント要らない。

```ruby:~/.gemrc
install: --no-rdoc --no-ri
update:  --no-rdoc --no-ri
```

## Rails
Railsをインストールして準備完了。

```
$ gem install rails --version 4.0.1
```

```
$ ruby -v
ruby 2.0.0p353 (2013-11-22 revision 43784) [x86_64-darwin13.0.0]
$ rails -v
Rails 4.0.1
$ gem -v
2.1.11
```

# プロジェクト作成
rails newする。

```
$ cd /path/to/project/dir/
$ rails new project_name --skip-test-unit --skip-bundle
$ cd project_name
```
* RSpecをつかうのでtest::unitを組み込まない(--skip-test-unit)
* 勝手にbundle installさせない(--skip-bundle)

## Gemfile
```ruby:Gemfile
source 'https://rubygems.org'

ruby '2.0.0'
#ruby-gemset=project_name_rails_4_0
gem 'rails', '4.0.1'

gem 'bootstrap-sass', '3.0.0.0'

group :development, :test do
  gem 'sqlite3', '1.3.8'
  gem 'rspec-rails', '2.14.0'
end

group :test do
  gem 'rspec', '2.14.0'
  gem 'selenium-webdriver', '2.37.0'
  gem 'capybara', '2.1.0'
end


gem 'sass-rails', '4.0.0'
gem 'uglifier', '1.3.0'
gem 'coffee-rails', '4.0.0'
gem 'jquery-rails', '3.0.4'
gem 'turbolinks', '1.3.1'
gem 'jbuilder', '1.2'

group :doc do
  gem 'sdoc', '0.3.20', require: false
end

group :production do
  gem 'pg', '0.17.0'
  gem 'rails_12factor', '0.0.2'
end
```
* ruby-gemsetを設定しておくとフォルダ移動したとき自動的に切り替わるので便利。（先頭#はそのまま）
* Heroku向けにproductionはPostgreSQL。testとdevelopmentはSQLite。

## bundle
--without productionオプションでproduction以外はgemをインストールする。

```
$ bundle install --without production
$ bundle update
$ bundle install
```
* 以降、productionがwithoutなことを覚えてくれる

## RSpec
RSpecを使う設定。

```
$ rails generate rspec:install
$ bundle exec rspec spec/
```

## 秘密トークン
セッション変数の暗号化に使う秘密トークンを動的に生成するように変更。
Githubのような公開レポジトリにファイルを置く場合は要注意。

```ruby:config/initializers/secret_token.rb
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.

# Make sure your secret_key_base is kept private
# if you're sharing your code publicly.
require 'securerandom'

def secure_token
  token_file = Rails.root.join('.secret')
  if File.exist?(token_file)
    # Use the existing token.
    File.read(token_file).chomp
  else
    # Generate a new token and store it in token_file.
    token = SecureRandom.hex(64)
    File.write(token_file, token)
    token
  end
end

ProjectName::Application.config.secret_key_base = secure_token
```

生成される.secretを.gitignoreに登録。

```:.gitignore
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
#   git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config.
/.bundle

# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal

# Ignore all logfiles and tempfiles.
/log/*.log
/tmp

# Ignore other unneeded files.
doc/
*.swp
*~
.project
.DS_Store
.idea
.secret
```

## 実行
サーバ開始。

```
$ rails s
$ open http://0.0.0.0:3000
```

## Git
コミットしておしまい。

```
$ git init
$ git add .
$ git commit -m "Initial commit"
```

# Scaffoldで簡単デモ

何か試したい場合はブランチを切っておくと安心。

```
$ git checkout -b todo-pages
```

> 元に戻る
>> $ git checkout master
>
> マージする
>> $ git mearge todo-pages
>
> 削除する
>> $ git branch -d todo-pages
>
> 強制削除
>> $ git branch -D todo-pages

## Todoページ作成
-pオプションで何が生成されるのか確認。

```
$ rails g scaffold Todo title:string task:string -p
      invoke  active_record
      create    db/migrate/yyyyMMddHHmmss_create_todos.rb
      create    app/models/todo.rb
      invoke    rspec
      create      spec/models/todo_spec.rb
      invoke  resource_route
       route    resources :todos
      invoke  scaffold_controller
      create    app/controllers/todos_controller.rb
      invoke    erb
      create      app/views/todos
      create      app/views/todos/index.html.erb
      create      app/views/todos/edit.html.erb
      create      app/views/todos/show.html.erb
      create      app/views/todos/new.html.erb
      create      app/views/todos/_form.html.erb
      invoke    rspec
      create      spec/controllers/todos_controller_spec.rb
      create      spec/views/todos/edit.html.erb_spec.rb
      create      spec/views/todos/index.html.erb_spec.rb
      create      spec/views/todos/new.html.erb_spec.rb
      create      spec/views/todos/show.html.erb_spec.rb
      create      spec/routing/todos_routing_spec.rb
      invoke      rspec
      create        spec/requests/todos_spec.rb
      invoke    helper
      create      app/helpers/todos_helper.rb
      invoke      rspec
      create        spec/helpers/todos_helper_spec.rb
      invoke    jbuilder
      create      app/views/todos
      create      app/views/todos/index.json.jbuilder
      create      app/views/todos/show.json.jbuilder
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/todos.js.coffee
      invoke    scss
      create      app/assets/stylesheets/todos.css.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.css.scss

$ git status
# On branch todo-pages
nothing to commit, working directory clean
```
* acrtive_record
    * TodoモデルのDB(db/migrate/yyyyMMddHHmmss_create_todos.rb)
    * Todoモデルの定義(app/models/todo.rb)
    * TodoモデルのRSpec(spec/models/todo_spec.rb)
* resource_route
    * /todosへのルーティング(resources :todos)
* scaffold_controller
    * Todoコントローラー(app/controllers/todos_controller.rb)
    * Todoビュー(*.erb)
    * TodoコントローラのRSpec(spec/controllers/todos_controller_spec.rb)
    * TodoビューのRSpec(*.erb_spec.rb)
    * /todosのRSpec(spec/requests/todos_spec.rb)
    * Todoヘルパー(app/helpers/todos_helper.rb)
    * TodoヘルパーのRSpec(spec/helpers/todos_helper_spec.rb)
    * TodoのJbuilder（ってなんぞ？）
* assets
* scss


問題なさそうなら適用してマイグレーション。

```
$ rails g scaffold Todo title:string task:string
$ bundle exec rake db:migrate
```

## ドキュメントルート
このままだとTopに何も表示されないので、todos#indexをページトップに。

```ruby:config/routes.rb
ProjectName::Application.routes.draw do
  resources :todos

  root 'todos#index'
end
```

## 動作確認
サーバを起動。

```
$ rails s
$ open http://0.0.0.0:3000
```

コミットしておく。

```
$ git add .
$ git commit -m "Add TODO pages"
```

## Heroku
まず前準備。

```
$ heroku login
$ heroku create
```

ブランチをHerokuにデプロイ。要コミット。

```
$ git push heroku todo-pages:master
$ heroku run rake db:migrate
$ heroku open
$ heroku logs
```

デプロイに失敗する場合。

```
$ rake assets:precompile
$ git add .
$ git commit -m "Add precompiled assets for Heroku"
$ git push heroku todo-pages:master
```

# RSpec
TDDでサイト開発。

```
rails g controller StaticPages top --no-test-framework
```
* コントローラとビュー(top)を生成
* テストは後で追加するので(--no-test-framework)

ルーティング修正してルートをtopに。

```ruby:config/route.rb
ProjectName::Application.routes.draw do
  root 'static_pages#top'
end
```

テスト生成。

```
$ rails g integration_test static_page
```

Capybaraからpage変数をもらってアクセスした内容をテスト可能に。

```ruby:spec/spec_helper.rb
RSpec.configure do |config|
  ...
  config.include Capybara::DSL
end
```

"ProjectName"がページトップに表示されればテスト成功とする。

```ruby:spec/requests/static_pages_spec.rb 
require 'spec_helper'

describe 'StaticPages' do
  subject { page }
  describe 'Top page' do
    before { visit root_path }
    it { should have_content('ProjectName') }
  end
end
```

テストが失敗することを確認。

```
$ bundle exec rspec spec/
1 example, 1 failure
```

テスト内容に合わせてページを修正。

```html:app/views/static_pages/top.html.erb
<h1>ProjectName</h1>
```

テストが通ることを確認。

```
$ bundle exec rspec spec/
1 example, 0 failures
```
> DBマイグレーションが必要なテストは
>> $ bundle exec rake test:prepare
>
> を忘れないこと。

## Bootstrap
CSSを追加。

```css:app/assets/stylesheets/custom.css.scss
@import "bootstrap";
```

JavaScriptを追加。

```Javascript:app/assets/javascripts/application.js
...
//= require bootstrap
//= require_tree .
```

Asset Pipelineとの互換性。

```ruby:config/application.rb
...
module ProjectName
  class Application < Rails::Application
    ...
    config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
  end
end
```

TopページをBootstrapに。

```HTML:app/views/static_pages/top.html.erb
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
  <div class="container">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">ProjectName</a>
    </div>
  </div>
</div>
```

黒いナビバーに"ProjectName"が表示される。

```
$ open http://0.0.0.0:3000
```