この記事は「Rails初級者が一ヶ月研修を受けて得た学びをまとめた - Qiita」のRailsに関する項目を切り出した分割記事です
概要などについては親記事を参照してください。
Rubyの文法など基本的なこと
配列の種類
-
%i
:シンボル配列。メソッド名、変数名などの配列を作るときに
Hashは省略記法が使える
- Ruby3.1から対応
- Hashの値の省略記法 - NaCl非公式ブログ
-
{ x: x, y:y }
->{ x:, y: }
pp pp puts printの使い分け
enumの挙動に注意
-
key,valueどちらを渡してもsaveは成功する
-
DBにはvalueで保存される
ActiveRecord上ではenumのkey名として保持して、DBに保存する時に数値で変換して保存してくれます
-
Task.status
が{ yet: 0, ongoing: 1, complete: 2 }
のようになっていた場合、Task.ongoing
でTask.where(status: 'ongoing')
と同じことが実行さる。 -
このようなカラムに
numericality: { only_integer: true }
などのvalidationをつけるとkey名でsaveできなくなるので注意 -
付与するvalidationも
presence: true
程度で良いなので独自に追加するのは presence: true 程度で良いかと思います。
記事とかだと inclusionを指定しているようなものもありますが、上記通りRails側で指定したenumのkey / value以外をしてしようとするとエラー発生してくれるのでinclusionも必要ありません。 -
この仕様がわかっておらず騒いでいる初心者のアホ→railsのenum型で沼
-
enumについてはここが参考になった 【Rails】5ステップでイケてる enum を作る(翻訳) - Qiita
Rails実装に関すること
Gemfile内でのgroup指定
- rubocopなど本番環境で利用しないものは適切にgroup指定をする
- ref:https://bundler.io/guides/groups.html
現在アプリ側で利用されているDB設定を確認する
- envを利用して参照するDBをDockerコンテナ内とローカルDBとを切り替えたりしていた
- その際「この環境変数とconfigちゃんと有効になっている?」と気になったときに使った
-
Rails.application.config.database_configuration
で参照できる - ref: Rails ActiveRecord 現在のDB設定を確認する方法 | ふらっと考える
ユーザビリティー・インターフェイス
errorメッセージが日本語で出るようにi18nを適応させる
- ユーザーフレンドリーなのでやっておこう
enumはi18nとgemで日本語化できる
- 例えばタスクの優先度をこのようなenumで定義していた場合
class Task < ApplicationRecord .... enum priority: { low: 0, middle: 1, high: 2 }
- フロントで表示する際は
低、中、高
としたい - その時は
enum_help
で定義できる - 便利なheler_methodも用意されている
- 間違っても
enum priority: { 低:0, 中:1, 高:2 }
のような定義をmodelでしないこと - refs
created_at/updated_atのRailsが自動付与カラムはユーザー向けには使わない
- 手動データ修正した際にずれる可能性が高い。
- 日付けソートなどの機能を提供したい場合は専用の別カラムを用意した方が良い。
APIのパラメータは使い手に理解しやすく
- Rails側でしかわからないことは含ませない=内部実装は隠す
- 理解しやすいインターフェイスに
- これま同じメンバーが実装するフロントでコールするAPIしか設計してこなかったため、この辺りの意識が足りていなかった
- スマホアプリ開発チーム側で使われるAPIを設計していくことになるのでしっかり意識する必要がある
メソッド
controller内で利用する定数はprivate_constantつけとくとよい
- あと、定数はアッパーケースで
- 例えば
tasks_controller
内のメソッドで利用する定数の場合このように書いておくと良いclass TasksController < ApplicationController ... SORTABLE_COLUMN = { name: 'task_name', detail: 'detail', limit: 'date_limit', status: 'status', priority: 'priority' }.freeze private_constant :SORTABLE_COLUMN
- 他殻も参照できてしまうのでできるだけスコープは狭く
- 定数定義の仕方は色々あるみたい
methodの説明などのコメントはYARD記法で
- YARDはmethodの引数、戻り値などを記載できるDoc記法
- IDEでの型推論に役立つのでどうせ書くならYARDで書こう
- ref: Rails/Rubyドキュメントをキレイに生成するYARD、早見表付き! | 酒と涙とRubyとRailsと
method名にset
やget
,has
は使わないようにする
- factory_botに怒られる
動的にwhereをつけたい時はcompact
を使うと良い
- 例えばクエリパラメータに
status=low
が含まれている場合だけTask.where(status: params[:status])
を付与したい…# bad @tasks = params[:status] ? @tasks.where(status: params[:status]) : @tasks #good @tasks = @tasks.where({ status: params[:status] }.compact)
- このようにhashで渡してやれば
compact
が省略してくれ、where句自体が実行されない - なお実際は
@tasks.where({ status: Task.statuses[params[:status]] }.compact)
として不正なリクエストパラメーターをクエリに渡さないようにしている
errorレンダリング関数名はHTTPステータスのシンボルで定義すると良い
- 例えば503エラーページをrenderさせる場合
- bad:
def render_503 ... end
- good:
def render_service_unavailable ... end
- bad:
- ref: レイアウトとレンダリング - Railsガイド
controllerでのメソッド呼び出しの仕方
-
actionメソッドで利用するTaskのインスタンスの呼び出し方についてこのような定義をしていた
- それぞれのcotrollerメソッドの前に
before_action
で@task
にインスタンスを格納し、それをメソッド内で参照していた
before_action: :task .... def update @task = 必要な処理 @task.update end def destroy @task.destroy end def task @task = Task.find[params[id]] end
- それぞれのcotrollerメソッドの前に
-
PRで提案された記法がこう
# before_action: :task def update task.update .... end def destroy task.destroy end private def task @task ||= Task.find(params[:id]) end
point
-
||=
を使い、同一メソッド内で呼び出された場合は、DBへの再参照が起きなようにしている- ref: 演算子式 (Ruby 3.1 リファレンスマニュアル) -自己代入
- すでに値が定義済みなら再代入しない
-
privateメソッドでタスクインスタンスを定義し、メソッドを呼び出して関数内でも利用する。(railsっぽい書き方らしい)
-
before_action
でセットされたインスタンス変数を使うとactionコードだけ見たときにわかりづらいから
-
-
Q.
getterメソッドで対応し、インスタンスに直接アクセスしない様にするのは何かアーキテクチャ的理由があるのでしょうか?
-
A.
クラス内部でインスタンス変数を参照するのは全然構わないと思います!(人によっては getter メソッドに統一する人もいる)
今回のでいうと、各アクションでは before_action で事前にセットされたインスタンス変数にアクセスしていますが、アクションのコードだけ見るとその前提が分かりづらいので、分かりやすい形にしておきたいって感じですかねー
こういう時はこういう風に書くというのが大体決まっているので、そこから外れないように書くと他の人にも読みやすいコードになるかと思います!(こういう風というケースは、他の人のコードを読んで学習するのが一番👍)
redirect_toは引数の指定の仕方に注意
redirect_toは3xx以外のstatusを渡すと正常に動かない
-
redirect_toはリダイレクト先とHTTPstatusを渡すことができる
-
「ここに任意のstatusを与えて使えますよ〜」と書いてある記事は多いが、実際は3xx以外渡すと動かなかった
-
例えば201を渡すとこんな感じ
↳ app/controllers/tasks_controller.rb:41:in `create' Redirected to http://localhost:3000/tasks/new Completed 201 Created in 76ms (ActiveRecord: 48.7ms | Allocations: 12669) ## ↑ここでredirect処理自体は終わっている ## ↓ここからは? Started GET "/tasks" for ::1 at 2022-08-25 17:51:19 +0900 Processing by TasksController#index as HTML
-
http://localhost:3000/tasks/new
にリダイレクトされる処理が完了してしまっているが、GETが走っていない。 -
その代わり、直後に謎の力で
root_path
へのGETメソッドが走っている -
specで同様のことをしてもこの挙動は起きないため、railsの何らかのおせっかいで
root_path
に飛ばしてくれている? -
redirect_to
の公式にも3xx以外だと動かないよ!
としか書かれていない rails/redirecting.rb rails/rails
erb
deleteメソッドはlink_to
ではなくbutton_to
で
- Rails7からJS仕様が変更になり
link_to
でDELETE
メソッドを使うとGET
になってしまう - devise - Rails 7 - link_to with method :delete still performs GET request - Stack Overflow
- Rails7でmethod: :deleteの扱い - KATSUSHI-OUGI.COM
-
button_to
を使いましょう
<% %>
と<%= %>
は別物
- これは完全に自分がアホ
-
<% %>
-> 結果がレンダリングされない -
<%= %>
-> 結果がレンダリングされる - Action View の概要 3.1.1 ERB - Railsガイド
erbLintを入れてerbの整形を
Deviseで使われている認証フレームワークWarden
- Wardenの使い方 まとめ - 猫Rails
- 直接触ってはいないが、Deviseで実装したサインイン機能をrspecで呼び出す際に勉強した気がする。
- 深追いはしない
migrationはbulkupdateで行うと良い
-
rubocopの
Rails/BulkChangeTable: You can use change_table :tasks, bulk: true to combine alter queries.
でも指摘される -
先輩も
migrationファイルで実行されるSQLは1トランザクションで完結するべきと考えていて、それを半強制するこのルールは好きです。
とおっしゃっており、ベターっぽい
# bad def up change_column .... change_column .... end # good def up change_table(:tasks, bulk: true) do |t| t.index ... t.chage_default ... end end
-
使い方はこちらを参照:change_table | Railsドキュメント