Railsの使い方まとめ

# Railsインストール・プロジェクト作成
## Railsインストール

```
$ gem install rails
```

## プロジェクト作成

```
$ rails new hoge
MySQL使う場合
$ rails new hoge --database=mysql

```

# モデル作成・マイグレーション

## モデル
Controllerは複数形、modelは単数形。

`$ rauls g model User name:string email:string`を実行すると、マイグレーションファイルが作成される。作成されたマイグレーションファイルをDBに反映されるために、`$ rails db:migrate`を実行する。

## モデルの作成・削除

```
$ rails g model User name:string email:string
$ rails destroy model User
```

### マイグレーションファイル作成が不要の場合
モデル作成時のマイグレーションファイルの作成が不要な場合、`--migration false`をつける。

```
$ rails g model User --migration false
```

## モデルの更新

モデルのフィールドを変更したい場合、下記でマイグレーションファイルを作成する。

```
$ rails generate migration add_index_to_users_email
$ rails db:migrate
```

### 既存DBからプロジェクト作成する場合
[Rails - schema.rb（既存DBを使ったアプリ作成）](http://qiita.com/edo1z/items/a0bf22b294406f00ec7c)

## モデルのValidation

```app/models/user.rb
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }
end
```

## マイグレーション

```
$ rails db:migrate
$ rails db:migrate RAILS_ENV=production #本番環境DB作成
$ rails db:rollback #1つ前に戻る
$ rails db:migrate VERSION=0 #最初に戻る
$ rails db:migrate:reset #DBをリセット
```
[Rails - マイグレーション](http://qiita.com/edo1z/items/472606884bedffb661f1)

# コントローラの作成・ルーティング

## コントローラ作成・削除

```
$ rails g controller StaticPages home help
$ rails destroy controler StaticPage home help
```

## ルーティング

`resources :users`と書くと、usersの規定のルーティングが反映される。

```config/routes.rb
Rails.application.routes.draw do
  root   'static_pages#home'
  get    '/help',    to: 'static_pages#help'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users
  resources :account_activations, only: [:edit]
end
```

### 規定のルーティング
規定のルーティングは下記。

| HTTP Req | URL         | action | name                |
|:--------:|:------------|:------:|:-------------------:|
| get      |/users       | index  |users_path           |
| get      |/users/1     | show   |user_path(user)      |
| get      |/users/new   | new    |new_user_path        |
| post     |/users       | create |users_path           |
| get      |/users/1/edit| edit   |edit_user_path(user) |
| patch    |/users/1     | update |user_path(user)      |
| delete   |/users/1     | destroy|user_path(user)      |

### rails routes

ルーティングの状態を確認できる。

```
$ rails routes
```

## Link

リダイレクトのときは、hoge_urlを使って、あとは、hoge_pathを使う。

```
<%= link_to "About", about_path %>

root_path -> '/'
root_url -> 'http://hoge.com/'
help_path -> '/help'
help_url -> 'http://hoge.com/help'
```

# ユーザ登録・ログイン・アクセス制限

devise（ユーザ登録・ログイン）と、cancan（アクセス制限）というgemを使うことで、実現するのが割と一般的。

- [Rails - deviseやってみる](http://qiita.com/edo1z/items/e249f2eee1432f95c857)
- [Railsで管理画面をつくってみる](http://qiita.com/edo1z/items/3de1b1dc52f2c52d5ec9)

# Railsコマンド

## Rails Commandの短縮形

```
$ rails g (generate)
$ rails c (console)
$ rails s (server)
$ rails t (test)
$ bundle (bundle install)
```
## gemfile -> bundle install

```
$ bundle install
$ bundle install --without production
$ bundle update
```

## rails server

`--environment production`をつけると本番環境になる。

```
$ rails s --environment production
```

## Scaffold

scaffoldでモデル・コントローラ・規定のルーティングとかもろもろ作成される。Migration Fileも作成されると思う。migrateでテーブルにモデルの内容が反映される。

```
$ rails generate scaffold User name:string email:string
$ rails db:migrate
```

## rails console

`--sandbox`を付けると、DBを更新しないモードになる。testをつけるとテスト環境になる。

```
$ rails c
$ rails c --sandbox
$ rails c test
```

### irbの設定

この設定によりirbのプロンプトが簡潔な表示に置き換えられ、irbの邪魔な自動インデント機能がオフになります。

```~/.irbrc
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.conf[:AUTO_INDENT_MODE] = false
```




## パスワードのハッシュ化

### bcrypt追加
bcryptというハッシュ関数のgemが必要。

```Gemfile
gem 'bcrypt', '3.1.11'
```

### Modelに追記
Modelに、`has_secure_password`を追加する

```app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  has_secure_password
end
```

### 出来るようになること

自動化半端ない。

- セキュアにハッシュ化したパスワードを、データベース内の`password_digest`という属性に保存できるようになる。
- 2つのペアの仮想的な属性 (`password`と`password_confirmation`) が使えるようになる。また、存在性と値が一致するかどうかのバリデーションも追加される 。
- `authenticate`メソッドが使えるようになる (引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド) 。

### ログインチェック

`authenticate`メソッででチェックできる。

```
>>user = User.find_by(email: 'hoge@hoge.com')
>>user.authenticate(password)
true
```

### ログインメソッド

上記ログインチェックがTrueだったら、下記でログインさせることができる。

```
session[:user_id] = user.id
```

#### Helperに書く例

```app/helpers/sessions_helper.rb
module SessionsHelper

  # 渡されたユーザーでログインする
  def log_in(user)
    session[:user_id] = user.id
  end
end
```

### ログイン用のSessionControllerの例

```app/controllers/sessions_controller.rb
class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
  end
end
```

### ログイン中ユーザの取得

```
@current_user ||= User.find_by(id: session[:user_id])
```

上記は、下記と同じ。

```
@current_user = @current_user || User.find_by(id: session[:user_id])
```

#### Helperに書く例

```app/helpers/sessions_helper.rb
module SessionsHelper

  # 渡されたユーザーでログインする
  def log_in(user)
    session[:user_id] = user.id
  end

  # 現在ログイン中のユーザーを返す (いる場合)
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end
end
```





# View

## Form

こんな感じ。cakephpより全然いいけど、どれも似ている。`<%= render 'shared/error_messages' %>`というのは、全Viewに対して有効なパーシャルを読み込んでいる。

```app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: signup_path) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
```

## 上のパーシャル
```app/views/shared/_error_messages.html.erb
<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>
```
## 上記に対応するコントローラ

```app/controllers/users_controller.rb
class UsersController < ApplicationController
  
  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end
```

## flash message

`flash[:success]`でflash messageを登録できる。

Viewに表示させるためには、下記のようにする。

```
<% flash.each do |message_type, message| %>
  <div class="alert alert-<%= message_type %>">
    <%= message %>
  </div>
<% end %>
```

下記が出力されるようになる。

```
<div class="alert alert-success">Welcome to the Sample App!</div>
```

# Helper

Controllerに関連付けすることで、Controllerに対応する全てのViewでHelperを利用できるようになる。（関連付けしないとデフォルトで全てのViewで使えるのかもしれない。）

```app/helpers/users_helper.rb
module UsersHelper

  # 引数で与えられたユーザーのGravatar画像を返す
  def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end
```

## ControllerにHelperをインクルードする

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper
end
```

これをViewで使う。

```app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>
```


# Layout

```app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag 'application', media: 'all',
     'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',  
     'data-turbolinks-track': 'reload' %>
    <%= render 'layouts/shim' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <% flash.each do |message_type, message| %>
      <div class="alert alert-<%= message_type %>"><%= message %></div>
    <% end %>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>
```

## パーシャル

パーシャルはcakephpのelementみたいなやつ。

```app/views/layouts/_shim.html.erb
<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
  </script>
<![endif]-->
```

```app/views/layouts/_header.html.erb
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="container">
    <%= link_to "sample app", '#', id: "logo" %>
    <nav>
      <ul class="nav navbar-nav navbar-right">
        <li><%= link_to "Home",   '#' %></li>
        <li><%= link_to "Help",   '#' %></li>
        <li><%= link_to "Log in", '#' %></li>
      </ul>
    </nav>
  </div>
</header>
```

# Asset

- app/assets: 現在のアプリケーション固有のアセット
- lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット
- vendor/assets: サードパーティのアセット

## Bootstrap + Sass

```Gemfile
gem 'bootstrap-sass', '3.3.6'
```

```app/assets/stylesheets/custom.scss
$ bundle
$ touch app/assets/stylesheets/custom.scss
```

```
@import "bootstrap-sprockets";
@import "bootstrap";
```

# Debug
`debug()`をviewに追加する。

```app/views/layouts/application.html.erb
<%= debug(params) if Rails.env.development? %>
```

# 開発環境

テスト(test)、開発(development)、本番(production)がある。デフォルトはdevelopment。railsにはRailsオブジェクトがあり、env属性がある。`Rails.env.test?`はテスト中ならtrueを返す。

## SSL接続

本番環境のSSL接続を強制する。全てが簡単だ。httpでアクセスしたらhttpsにリダイレクトされるのかな。

```config/environments/production.rb
Rails.application.configure do
  .
  .
  config.force_ssl = true
  .
  .
end
```