Open60

Laravel経験者が「Rails チュートリアル」流し読みする

kyamadkyamad

※特に明示しない限り、引用は全てRailsチュートリアルからの引用を示しています

1章開始

  • Railsをインストールしたい時:gemを使う
  • bundlerをインストールしたい時:gemを使う
  • Yarnとは何:JavaScript依存関係マネージャ
  • Webpackerとは何:フロントエンドビルドシステム。Rails用。「JavaScript」「CSS」「画像やフォント」といった静的アセットを管理。
kyamadkyamad
$ bundle _2.2.17_ install

これの数字なに?

kyamadkyamad

bundlerのバージョン。自分で指定できるのかな?

kyamadkyamad
$ bundle _2.2.17_ config set --local without 'production'
$ bundle _2.2.17_ install

パッケージインストール用のコマンド。 --local without 'production' で開発用のパッケージをインストールできる

kyamadkyamad
$ rails webpacker:install

rails の webpacker install コマンド。なんでrailsからインストール?これはプロジェクト毎にインストールするタイプのライブラリなのかな?
プロジェクト毎にバージョン違ったりする?

kyamadkyamad
class ApplicationController < ActionController::Base

  def hello
    render html: "hello, world!"
  end
end

rails のコントローラ側でのレンダリング処理。
文法違うだけ。viewの読み込みについては後述。

kyamadkyamad

命名
app/controllers/application_controller.rb
こんな感じでスネークケース(そういやそうだったな)

Laravelとベストプラクティス違いそう。
RoR用の命名規則表などあると思うのであとで調べる。

kyamadkyamad

scaffold実行コマンド。めっちゃ関連ファイル吐いてる。すご。
testまで、、、素晴らしい。

$ rails generate scaffold User name:string email:string
      invoke  active_record
      create    db/migrate/20190820002503_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route  resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      create      test/system/users_test.rb
      invoke    helper

      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss
kyamadkyamad

migrateコマンド。ほぼ Laravel と一緒

$ rails db:migrate
kyamadkyamad

(:usersという一見奇妙な記法は、Ruby言語特有の「シンボル」と呼ばれるものです。詳細については4.3.3で説明します)。

シンボルなるものが存在すると、、、少しだけ頭に入れておく。

kyamadkyamad
root 'application#hello'

ルーティングの時にアクションを指定する場合は#のあとにアクション名を記載。Laravelとほぼ同じ。

kyamadkyamad
Rails.application.routes.draw do
  resources :users // こいつ気になる。
  root 'users#index'
end
kyamadkyamad
class UsersController < ApplicationController
  .
  .
  .
  def index
    @users = User.all
  end
  .
  .
  .
end

User.allが噂のあれ(Active Record)か。これはすごい。

kyamadkyamad

下のコントローラーとビューの例だと変数の渡し方明示していないよね?

@記号で始まる変数をRubyではインスタンス変数と呼び、Railsのコントローラ内で宣言したインスタンス変数はビューでも使えるようになります。

らしい。すご。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def index
    @users = User.all
  end
  .
  .
  .
end
app/views/users/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Users</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete,
                         data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New User', new_user_path %>
kyamadkyamad
Rails.application.routes.draw do
  resources :microposts
  resources :users
  root 'users#index'
end

resourceの定義の仕方

kyamadkyamad
class Micropost < ApplicationRecord
  validates :content, length: { maximum: 140 }
end

ここの記法気になるな。。。validation調べよう

kyamadkyamad

全体的に記法がタイプ数少なくて済みそう

kyamadkyamad

リレーション、バリデーションは特に困ることもなさそう

kyamadkyamad

Gemfileはパッケージ管理のためのファイル。バージョンとパッケージ名を指定する。

kyamadkyamad

1.4.4で学んだことを思い出しましょう。Gitを使う場合は、masterブランチでずっと作業するのではなく、その都度トピックブランチを作成して作業するのがよい習慣です。Gitでバージョン管理を行っているのであれば、次のコマンドを実行して、静的なページ用のトピックブランチをチェックアウトしましょう。
~Rails チュートリアル

大事

kyamadkyamad

一般的なシナリオの1つは、生成したコードを元に戻したい場合です。例えばコントローラを生成した後で、もっといいコントローラ名を思い付き、生成したコードを削除したくなった場合などです。リスト 3.7のように、Railsはコントローラ以外にも関連ファイルを大量に生成するので、生成されたコントローラファイルを削除するだけでは元に戻りません。自動生成されたコードを元に戻すためには、新規作成されたファイルを削除するだけではなく、既存のファイルに挿入されたコードも削除する必要があります(実際、2.2や2.3でも説明したように、rails generateを実行するとルーティングのroutes.rbファイルも自動的に変更されるので、これも元に戻さなくてはなりません)。このようなときは、「generate」という言葉に因んで、rails destroyというコマンドを実行することで元に戻すことができます。例えば次の2つのコマンドは、自動生成と、それに対応する取り消し処理の例です。
~Rails チュートリアル

はぇ~確かにそういうコマンドが間違えた時大変だもんなぁ。関連ファイル多すぎて

kyamadkyamad

Routing

get 'static_pages/home'

スラッシュで記述するとStaicPagesコントローラのhomeアクションとを紐づける。

kyamadkyamad

StaticPagesコントローラは一般的なRESTアクションに対応していないことに注意してください。これは、静的なページの集合に対しては、適切なアクションと言えます。言い換えると、RESTアーキテクチャは、あらゆる問題に対して最適な解決方法であるとは限らないということです。
Rails チュートリアル

RESTの利点はデータへの操作をURLで表現する能力が高いことなので、静的サイトだとそんなに。(削除とか更新とかしないから)

kyamadkyamad

(たとえ何も書かれていなくても)Rails特有の振る舞いをします。具体的には、/static_pages/homeというURLにアクセスすると、RailsはStaticPagesコントローラを参照し、homeアクションに記述されているコードを実行します。その後、そのアクションに対応するビュー(1.3.3で説明したMVCのVに相当)を出力します。今回の場合、homeアクションが空になっているので、/static_pages/homeにアクセスしても、単に対応するビューが出力されるだけです。
rails チュートリアル

これすげぇ。ちょっと気味悪いけど笑
返り値返すー>その値を表示する
上記みたいなフローを明示的に書くのが普通だと思ってるから変な気分だ

kyamadkyamad

アプリケーションのコードよりも明らかにテストコードの方が短くシンプルになる(=簡単に書ける)のであれば、「先に」書く
動作の仕様がまだ固まりきっていない場合、アプリケーションのコードを先に書き、期待する動作を「後で」書く
~ Rails チュートリアル

これ良いな。こういうやりかただとTDDやっても上手くいきそう。
全部最初にテスト書こうとすると「どうやるんだっけ???」みたいになりそうだし。

kyamadkyamad

多くのテストツールでは、テストの失敗を red 、成功したときを green で表します。ここから、このサイクルを「 red ・ green ・ REFACTOR」
rails tutorial

これよく聞くやつ。

kyamadkyamad

例では以下のテストからRedGreenRefactorを開始してる。
結構以外だ。もっと細かくテスト定義してくもんかと。

その辺のバランス感覚覚えないとな

  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end
kyamadkyamad
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end
end

このへんのテストの記法よーわからん。
特に「get static_pages_about_url」とかのurlの記述。
どういう法則なんだこれ。
コントローラ名+アクション名+_url でいいんかな?

kyamadkyamad
<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>
    <p>
      This is the home page for the
      <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
      sample application.
    </p>
  </body>
</html>

ビューのあたりの記法に関して。
<% provide(:title, "Home") %> これだと値を表示しない。
<%= yield(:title) %> これだと値を表示する。

kyamadkyamad
<% provide(:title, "The Title") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    Contents
  </body>
</html>

yield, provide ペアで使う。
yield は挿入される場所と名前を示す。
provide はどこに挿入するかを示す。

kyamadkyamad
<!DOCTYPE html>
...

  <body>
    <%= yield %>
  </body>
</html>

引数なしの yield を呼び出すとページの内容を挿入する箇所を指定できる。
基本的にbody直下とかcontainer直下とかで使う。Laravelと一緒。

kyamadkyamad
root 'application#hello'

こんなかんじでhome(uri + '/' でアクセスしたとき)のアクションを指定できる

kyamadkyamad

Rubyにおいてnilは特別なオブジェクトです。Rubyのオブジェクトのうち、オブジェクトそのものの論理値がfalseになるのは、false自身とnilの2つしかありません。
その他のあらゆるRubyのオブジェクトは、ゼロですらtrueです。
〜rails チュートリアル

ゼロもtrueか。。。PHPerは混乱しそう😅

kyamadkyamad

ここで、Rubyのメソッドには「暗黙の戻り値がある」ことにご注意ください。これは、メソッド内で最後に評価された式の値が自動的に返されることを意味します
~ railsチュートリアル

面白いな。楽だ。

kyamadkyamad

そのメソッドに対応する「破壊的」メソッドを使います。破壊的メソッドの名前には、元のメソッドの末尾に「!」を追加したものを使うのがRubyの慣習です。

なるほど。これだとわかりやすくて良いな。(と思うと同時に値ぐりぐりやるときは!だらけになるのかな?🤔)

kyamadkyamad
>> 0..9
=> 0..9
>> 0..9.to_a              # おっと、9に対してto_aを呼んでしまっていますね
NoMethodError: undefined method `to_a' for 9:Fixnum
>> (0..9).to_a            # 丸カッコを使い、範囲オブジェクトに対してto_aを呼びましょう
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range を使うときは注意。全部に丸括弧付けておくのが無難?

kyamadkyamad

1つの重要な違いとして、ハッシュでは要素の「並び順」が保証されないという点があります 。もし要素の順序が重要である場合は、配列を使う必要があります。

へぇ並び順保証されないのか。なんか気持ち悪いな(連想配列とは別物...?)

kyamadkyamad

ハッシュテーブル的なもののほうが概念としては近いかな

名前ハッシュだし

kyamadkyamad
# メソッド呼び出しの丸カッコは省略可能。
stylesheet_link_tag('application', media: 'all',
                                   'data-turbolinks-track': 'reload')
# 上は以下のように書いても同じ
stylesheet_link_tag 'application', media: 'all',
                                   'data-turbolinks-track': 'reload'
# 最後の引数がハッシュの場合、波カッコは省略可能。
stylesheet_link_tag 'application', { media: 'all',
                                     'data-turbolinks-track': 'reload' }
# 上は以下のように書いても同じ
stylesheet_link_tag 'application', media: 'all',
                                   'data-turbolinks-track': 'reload'

記法が面白い。変な感じする

kyamadkyamad
>> class Word < String             # WordクラスはStringクラスを継承する
>>   # 文字列が回文であればtrueを返す
>>   def palindrome?
>>     self == self.reverse        # selfは文字列自身を表します
>>   end
>> end
=> :palindrome?

Stringを継承する
美しい

kyamadkyamad
>> class String
>>   # 文字列が回文であればtrueを返す
>>   def palindrome?
>>     self == self.reverse
>>   end
>> end
=> :String
>> "deified".palindrome?
=> true

String を拡張する

大丈夫なの。。。?

kyamadkyamad
get 'static_pages/help'
↓
get  '/help', to: 'static_pages#help'

任意のアクションに送るコード

kyamadkyamad
require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
  end
end

統合テスト例

kyamadkyamad
<li id="micropost-<%= micropost.id %>">

こんな感じでidを振っておくと後で便利。

kyamadkyamad

13.3.2マイクロポストを作成する
上のエラーメッセージようわからんんん

kyamadkyamad
Micropost.where("user_id = ?", id)

上の疑問符があることで、SQLクエリに代入する前にidがエスケープされるため、SQLインジェクション(SQL Injection)呼ばれる深刻なセキュリティホールを避けることができます。

セキュリティ

kyamadkyamad
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy
  .
  .
  .
end

has many relation

kyamadkyamad
resources :users do
  collection do
    get :tigers
  end
end

このコードは /users/tigers というURLに応答します(アプリケーションにあるすべてのtigerのリストを表示します)8 。

なにこれ?どういう仕組?