Ruby on Railsを触ってみる

# はじめに
RoRがどんなものか試してみたかった。
雑ですが、また同じことを調べなくて済むようにメモ。
ちなみにsqliteもお初。

# 前提
Ubuntu 16.04
Ruby 2.4.1p111
Rails 5.2.3
Sqlite 2.4.1p111

# プロジェクト作成
プロジェクト作成からscaffoldingまで。

```
## プロジェクト作成
$ rails new cafe
$ cd cafe/
## サーバ起動→http://localhost:3000でYay!が出ることを確認。
$ rails s
## 日記機能を生成
$ rails g scaffold diary title:string body:text 
## scaffoldingした機能がURLマッピングされていることを確認
$ rails routes
## scaffoldingの結果を元にDBにテーブルを追加する
$ rails db:migrate
```

ちなみにscaffoldするときのstringは省略可能。デフォルトの型はstringのため。

# DBにアクセスしてみる
"rails db"でDBコンソールにログインする。

```
### DBコンソール(sqlite)にログインする
$ rails db
### テーブル一覧を見てみる
sqlite> .tables
### テーブル定義を確認する
sqlite> .schema diaries
CREATE TABLE "diaries" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar, "body" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
### select結果にカラム名も出す
sqlite> .headers on
sqlite> .mode column
### SELECTしてみる
sqlite> SELECT * FROM diaries;
### sqliteコンソールを抜ける
sqlite> .quit
```

# Viewをいじってみる
更新日時を追加してみる。ヘッダとかも日本語にする。

```erb:app/views/diaries/index.html.erb
<p id="notice"><%= notice %></p>

<h1>日記一覧</h1>

<table>
  <thead>
    <tr>
      <th>タイトル</th>
      <th>本文</th>
      <th>更新日時</th> <!-- 追加 -->
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @diaries.each do |diary| %>
      <tr>
        <td><%= diary.title %></td>
        <td><%= diary.body %></td>
        <td><%= diary.updated_at %></td> <!-- 追加 -->
        <td><%= link_to '見る', diary %></td>
        <td><%= link_to '編集', edit_diary_path(diary) %></td>
        <td><%= link_to '削除', diary, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to '日記を新規作成する', new_diary_path %>
```

updated_atはscaffoldingの際に指定してないが、Railsが勝手に追加してくれる。


# 日付形式を変更する
最初はUTCになっているので、JSTに変更＆表示形式も変更する。

## JSTへ変更
config/application.rb　へ
config.time_zone = 'Tokyo'　を追加。

```rb:config/application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Cafe
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2
    config.time_zone = 'Tokyo'
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end
```

## time_formats.rb　の作成
以下を記入したconfig/initializers/time_formats.rbを作成する。

```rb:time_formats.rb
Time::DATE_FORMATS[:default] = "%Y/%m/%d %H:%M"
```

## 確認
再起動して更新日時が"%Y/%m/%d %H:%M"で表示されていることを確認。


# scaffoldとは
参照・登録・編集・削除の機能を持つアプリの雛形を作成するジェネレータコマンド。
コマンド１つで必要なファイルを一括して作成してくれるのでとても便利だが、
これしか使わないとRailsがいつまでたっても理解できないので乱用はよろしくないってよく言われるらしい。他の言語でプログラミングとかMVCの基礎を学んでいる人は別にいいと思う。もちろんscaffoldを使わない方法も知る必要がある。
以下でコントローラから機能を作成する手順も載せる。

# コントローラ生成からスタートして機能を作成する
## コントローラの生成
usersコントローラとそれが持つindexアクションを生成。
コントローラだけでなくビューなどいろいろ生成されていることがわかる。

```
$ rails g controller users index
Running via Spring preloader in process 9407
      create  app/controllers/users_controller.rb
       route  get 'users/index'
      invoke  erb
      create    app/views/users
      create    app/views/users/index.html.erb
      invoke  test_unit
      create    test/controllers/users_controller_test.rb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss
```

## 生成されたコントローラ

```rb:app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
  end
end
```

以下の通り、処理がない場合は紐づくビューが呼ばれる。
[Action Controller の概要 - 3 メソッドとアクション](https://railsguides.jp/action_controller_overview.html)
>ここでご注目いただきたいのは、newメソッドの内容が空であるにもかかわらず正常に動作するという点です。これは、Railsではnewアクションで特に指定のない場合にはnew.html.erbビューを描画するようになっているからです。

よって空のusers/indexアクションはapp/views/users/index.html.erbを返す。
※ちなみにerbは（embedded ruby）の略。

## ルーティング追加
config/routes.rbにgetの2行を追加。usersとusers/indexにアクセスがあった場合はusersコントローラのindexアクションを実行するという意味。

```rb:config/routes.rb
Rails.application.routes.draw do
  get 'users', to: 'users#index'
  get 'users/index', to: 'users#index'
  resources :diaries
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
```
## modelの生成
タイヤ、エンジン、ハンドルを属性に持つ車モデルを定義。
モデルクラスとマイグレーションファイルが生成されている。

```
$ rails g model car tire:string engine:string handle:string
Running via Spring preloader in process 12514
      invoke  active_record
      create    db/migrate/20190329170956_create_cars.rb
      create    app/models/car.rb
      invoke    test_unit
      create      test/models/car_test.rb
      create      test/fixtures/cars.yml
```

作成されたモデルクラスcar.rbを見ると処理は記載されていないがこのクラスがあるだけでcarsテーブルにアクセスできるようになる。

## マイグレーションの実行
Rails4まではrakeコマンドで行う必要があったが5からはrailsコマンドに吸収されたため以下のようにマイグレーションやroutesもrailsコマンドで実施できる。

```
$ rails db:migrate
== 20190329170956 CreateCars: migrating =======================================
-- create_table(:cars)
   -> 0.0024s
== 20190329170956 CreateCars: migrated (0.0025s) ==============================
```

このあとrails dbコマンドでDBコンソールを開いてcarsテーブルが作成されていることを確認。

# ERBの記述のルール
| 記号       |       動作 |    サンプル    |
|:-----------------|------------------:|:------------------:|
| <%  %> | コードとして実行 |<% if ＠test.present? %>Test<% end %>|
| <%=  %>|変数の中身を出力|       <%= ＠test %>       |

# コントローラからビューへ変数を渡す

```rb:app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @test='テストだよ！！'
    render template: 'users/index'
  end
end
```

```rb:app/views/users/index.html.erb
<h1>Users#index</h1>
<p><%= @test %></p>
<p><% if @test.present? %>test test test<% end %></p>
```

## 結果
Users#index
テストだよ！！
test test test

が画面に表示される。

# デザインの変更
共通のレイアウトは以下のファイルで定義されている。
app/views/layouts/application.html.erb
ここに共通で適用したいcssとかjavascriptを設定してあげればOK。

## ページごとにデザインを変えたい場合
### assetを追加する

```coffee:app/assets/javascripts/users.coffee
.users-index {
  font-size: 20px;
}
```

```scss:app/assets/stylesheets/users.scss
alert('Hi user!');
```

のように、coffeeまたはscssを配置する。（ファイル名はassets.rbに指定する）

### assets.rbのprecompileのコメントアウトを外す
指定するのはSprocketsによって変換された後のjs、css。

```rb:config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( users.js users.css )
```

サーバを再起動してポップアップが出ることと、文字がおっきくなっていることを確認。

# Sprocketsとは
coffeescriptやscssからJavascriptやcssを生成する仕組みを管理する。

# ActiveRecordとは
Railsが採用するO/Rマッパー。
SQLを使用せずにDBにアクセスする。
rails g modelコマンドでActiveRecordによるモデルクラスを生成する。
このコマンドを使用するとテーブル作成SQLを実行するためのマイグレーションファイルも作成してくれる。

# マイグレーションとは
テーブルの新規作成や変更を簡単に行うための仕組み。
DBMSによる違いを吸収して記述することができる。
以下はdiaryをg scaffoldした時のマイグレーションファイル。
timestampsはupdated_atなどのメタ情報。

```rb:db/migrate/20190328140515_create_diaries.rb
class CreateDiaries < ActiveRecord::Migration[5.2]
  def change
    create_table :diaries do |t|
      t.string :title
      t.text :body

      t.timestamps
    end
  end
end
```

# あとがき
ほんとはWindows+VSCodeで試したかったけど8年選手の低スペックマシンでは耐え切れなかったのでUbuntu16＋Atomで試しました。
次は簡単なWEBページを作成してみようと思います。