サカナ未遂

プログラミング、筋トレ、子育て

現場で使えるRuby on Rails 5 速習実践ガイドを読んだ

積読していた現場Railsを読みました。

全部読むの結構時間かかったけど、知らなかったこと、忘れていたこと結構あったのでそれらをまとめまた。

Chapter1

1-7 読めると便利! Rubyっぽい書き方

この辺りのイディオム、ちょくちょく見るし便利だけどいつも忘れる。

nilガード

number ||= 10

# number || (number = 10) と同じ動き

numberに値が入っていればそのまま、nilなら10を代入する。

ぼっち演算子

&.をつけてメソッドを呼び出すとレシーバがnilでもエラーが発生しない。

obj = nil

# objはnilなのでeachを使おうとするとエラーになる。
obj.each{|x| puts x }
NoMethodError: undefined method `each' for nil:NilClass

# ぼっち演算子をつけるとエラーにならない
obj&.each{|x| puts x }
=> nil

%記法

# %wは文字列の配列を生成する
%w(foo bar piyo)
=> ["foo", "bar", "piyo"]

# %iはシンボル の配列を生成する
%i(foo bar piyo)
=> [:foo, :bar, :piyo]

Chapter3

slimを使う。

下記を追加することで、slimが使える

gem 'slim-rails'
gem 'html2slim'

コマンドを実行することで既存のファイルをslimに変換してくれる

 bundle exec erb2slim app/views/layouts/ --delete

現職ではvueを使ってるので、slim使ったことなかった。pugみたいなもんか。

i18nでエラーメッセージを日本語にする

下記コマンドでja.ymlを取得してconfig/localesにおく。

wget https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml --output-document=config/locales/ja.yml

config/initialilzers/locale.rbに以下を記載する。

Rails.application.config.i18n.default_locale = :ja

リクエストパラメータ

GETでもPOSTでもパラメータの受け取り方をプログラマが区別しなくていいようにparamsが使える。 なんとなく使ってたけど、確かにGETでもPOSTでも同じように使えるのはRailsがやってくれてたのか。

レンダーとリダイレクト

レンダーはアクションに続けてビューを表示すること。リダイレクトはアクションを処理した直後にビューを表示せず別のURLに案内すること。

simple_format

以下のコード、hメソッドでXSS対応をした上で改行を
に変換し、さらに

タグで囲んでくれる。

simple_format(h(@task.description), {}, sanitize: false, wrapper_tag: "div")

Chapter4

バージョンを1つ戻してから1つ上げる。 バージョンが戻ることの確認とかに使う。

bin/rails db:migrate:redo

マイグレーションファイルのupとdown

マイグレーション失敗時に自動で戻せない場合に必要。 add_columnとかの場合の失敗は自動で戻してくれるから不要だけど、カラムにlimit: 30とか追加する時にはdownも書いておくと戻せる。downがないと例外が発生する。

validateのスキップ

falseを設定することでvalidateをスキップできる。

task.save(validate: false)

persisted?メソッド

オブジェクトがDBに登録されているかどうか確認ができる。

redirect_toのパラメータにmodelのオブジェクト

redirect_toのパラメータにmodelオブジェクトすると、showのページに遷移する。

validatesとvalidateの違い

標準の検証はvalidatesで自前の検証処理はvalidateになる。

パスワードのハッシュ化

has_secure_passwordを使うことでパスワードをハッシュ化できる。 使うにはbcrypt(gem)が必要。 has_secure_passwordをモデルに記述すると、passwordとpassword_confimartion属性が追加される。 2つの属性が一致した時だけパスワードを登録することができる。 テーブルにはpassword_digestの名前でカラムを用意しておく必要がある。これはhas_secure_passwordを使用するときの命名ルールである。

認証のためのauthenticate

authenticatehas_secure_passwordを記述した時に自動で追加される認証のためのメソッド。引数で受け取ったパスワードをハッシュ化して、オブジェクトに保存されてるdigestと一致するか調べる。

helper_method

コントローラにhelper_methodでメソッドを定義すると、viewからでも呼び出すことができる。

skip_before_action

before_actionをスキップすることができる。

Chapter5

Rspecについて

Rspecは動く仕様書として自動テストを書くという発想で作られてる。Rspecは「テスト」ではなく「Spec」を書くという気持ちが大事とある。 「動く仕様書」か、なるほどなるほど。 とりあえず書くもんだと今まで書いてきたけど、こういうフレームワークの思想みたいなものを知ることで、納得してテストを書いていける。

SystemSpecについて

FeatureSpecの代わりっぽい?、結局SPAでどうやるのか?と調べたらいけそう。 ここを見てみた。 tech.unifa-e.com

弊社ではE2EはRequestSpecしか書いてなかったけど、SystemSpecも導入した方が良いのかな。

visit

特定のURLでアクセスする。ログイン画面にアクセスする場合とかは以下のように記述する。

visit login_path

fill_in

パラメータで指定したラベルがついたテキストフィールドに値を入れる。 以下のように記述する

fill_in 'メールアドレス', with: 'a@example.com'

shared_examples_for

itなどを共通化することができる。

shared_examples_for 'タスクが画面に表示されること' do
  it { expect(page).to have_content 'タスク' }
end

コンソールのサンドボックス

Railsコンソールにサンドボックスあるの知らなかった〜。-s付ければいいのか

bin/rails c -s

Chapter6

CSRFはシーサーフと読まれることがある。

SQLインジェクションに気を付けるパターン

whereメソッドなどでSQL文字列を直接渡して条件指定するときはSQLインジェクションに気を付ける。 こんな場合

User.where("name = '#{params[:user_name]}'")

こっちにした方がいい。

User.where('name = ?', params[:user_name])

プレースホルダを使うと、「'」とかをエスケープしてくれる。

Chapter7

ransackを使うときに気を付けること

modelに以下のコードを入れることで特定のカラムに対してしかクエリーを発行できないようにすることができる。 下のコードは関連を指定できる。[]にすることで意図しない関連を含めないようにする。

def self.ransackable_attributes(auth_object = nil)
  %w[name created_at]
end

def self.ransakable_associations(auth_object = nil)
  []
end

mailcatcher

mailcatcherは送信したメールをブラウザ上で確認することができるgem コンソールから以下のコマンドで使える

mailcatcher

config/environments/development.rbに以下の設定をすると使える

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { address: '127.0.0.1', port: 1025 }

ActiveStorage

クラウドサービスにファイルをアップロードしてActiveRecordモデルに紐付けることが簡単にできる。 config/storage.ymlに保存先を設定する。 コメントアウトされているが、AWSやGCSも簡単に設定できる。

Chapter9

redoを習慣にする。

ロールバックできないトラブルを防ぐためにマイグレーションを書いたとき、ロールバックが成功することを確認することが重要。

マイグレーションファイルからアプリケーションコードの参照は避ける。

マイグレーションコードは積み重なっていくのでいつ実行しても同じように動く必要がある。 アプリケーションコードを使用する場合、その内容が変更(モデルにバリデーションが追加されるなど)したらマイグレーションファイルの挙動も変わってしまうため、避けた方が良い。

スキーマキャッシュ

マイグレーションファイルでモデルインスタンスを作成すると、ActiveRecordスキーマをキャッシュする。同じテーブルに対して連続してマイグレーションを行う場合、キャッシュが効いて意図しない挙動になることがあるので、reset_column_informationスキーマキャッシュを更新するよう習慣づける必要がある。

Chapter10

共通機能のモジュールのMix-in

RailsでMix-inのモジュールを書く時にはActiveSupport::Concernをextendする。 クラスレベルの拡張を素のrubyに比べて少し書きやすくしてくれる。

SIT

ActiveRecordモデルの継承する場合、継承元と継承先で1つのテーブルに対応づけを行うことをSIT(Single Table Inheritance)と呼ぶ。 対応づけらえるテーブルには継承されたテーブルが必要とするカラムを全部盛り込む必要がある。

複数のモデルがカラム処理は特定処理の専門家を作る

コントローラで2つのモデルを扱う処理の場合、片方のモデルにコードを書くと、他のモデルのデータの依存性を高めるのでよくない。 2つのモデルのデータを扱う専門のクラスを作成して処理を書くと良い。

サブリソース単位でコントローラを分割

コントローラは1つのモデルに対して1つでなければならないわけではない。 サブリソースへの操作を対応する複数のコントローラに分けることができる。

所感

まとめて感じたのは特にviewで使う機能に関する知識が結構欠落していること。 SPAがスタンダードになりつつあるので出番が減ってるのは確かだが、Railsを使って仕事をしていくなら最低限は覚えておかないとなぁとしみじみ思う。 あと、Chapter10は現場でかなり参考になる情報だった。定期的に読みなそうと思う。 いつ買ったのかAmazonの購入履歴で調べたら、買ってから2年も経ってた、、、もっと早く読んどけば良かった。 今年は積読消化を頑張らないと