ステータスコード
ステータスコードとは
そもそもRailsアプリケーションの仕組みは…
①HTTPサーバよりリクエストを受ける、リクエストはparamsで受け取った情報を元とする。
②リクエストをもとにrooterを経てcontrollerで該当のアクションを呼び出す。
③アクションよりmodelを使用しDBからレコードを引き出し、それをアクション内のインスタンス変数などに代入する。
④その情報をviewを元にHTMLを生成。レコードの情報が埋め込まれたHTMLが渡される。
⑤HTTPサーバを通って、HTMLがレスポンスとして送られる。
→すなわちどんな時でも、リクエストがあった時はレスポンスが返ってきて、ステータスコードが表示される!
ステータスコードはサーバーからのレスポンスの結果を表す、3桁の数字コードのこと。
ステータスコードの種類
100番台:情報レスポンス → 処理中の時
200番台:成功レスポンス → 成功した時
300番台:リダイレクションメッセージ → リダイレクトする時
400番台:クライアントエラーレスポンス → クライアント側でエラーが起こった時
500番台:サーバーエラーレスポンス → サーバ側でエラーが起こった時
ステータスコードの構造
プロトコルバージョンやステータスコードを記述した「ステータス行」
レスポンスするデータの情報などを記述した「ヘッダー」
ヘッダーによって定義される「本文」
から成り立つ。
関連するワード
head
headメソッドを使用することで、ヘッダだけで本文のないレスポンスをブラウザに送信できる。headメソッドには、HTTPステータスコードを示す多くのシンボルを引数として指定できる。
例えばcontrollerの条件分岐で失敗した時にhead :bad_request
とするとステータスコード400のヘッダだけのレスポンスが返ってくる。
参考URL
https://railsguides.jp/layouts_and_rendering.html#head%E3%81%A7%E3%83%98%E3%83%83%E3%83%80%E3%81%AE%E3%81%BF%E3%81%AE%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B
https://diveintocode.jp/blogs/Technology/ProcessFlow
https://www.itmanage.co.jp/column/http-www-request-response-statuscode/
https://digitalidentity.co.jp/blog/seo/seo-tech/howto-http-status-code.html
https://qiita.com/unsoluble_sugar/items/b080a16701946fcfce70
https://developer.mozilla.org/ja/docs/Web/HTTP/Status#successful_responses
https://developer.mozilla.org/ja/docs/Web/HTTP/Messages#http_responses
https://qiita.com/Knbass/items/d17910c53ffe64dff6a6
bundle exec と bin の違い
$ bin/
と$ bundle exec
の違いがよくわからないので調べてみた。
bundle execについて
Gemのパッケージ管理ツールBundlerによって使うことができる。
Gemfileに基づいて実行をするというコマンド。
たとえば$ bundle exec rspec
でRSpecを実行する際は、アプリケーション内のGemfileに設定してあるバージョンで実行できる。
$ rspec
だとローカル環境にインストールされているGemのRSpecを使用することになるため、バージョンが異なったり、インストールされてない場合は実行されない。
binについて
ググってみたがあんまりピンとこなかったが、現場Rails P65 で以下のような記述があり非常にわかりやすかった。
アプリケーションのルートディレクトリ直下のbinディレクトリにあるrailsというスクリプトを呼び出しています。このスクリプトを利用すると、「bundle exec rails」として実行した時と同様に、Gemfileどおりのgemを利用できる環境上でrailsコマンドを実行することができます。
それに加えて、SpringというRailsの起動を効率的に行う機能も組み込まれます。このように、よく使うコマンドを包み込んで使いやすくするスクリプトを「binstub」といいます。
つまりbinディレクトリ以下に設定してあるスクリプトは$ bin/rails
のように使うことができ、$ bundle exec rails
と同じように、そのアプリケーションのGemfileに設定してある環境でコマンドを実行することができるってこと。
また、$ bin/rspec
をしてみるとSpring is running
と自動的に設定されることも確認できる。ここが$ bundle exec
との違い。
ちなみにrailsコマンドについてはbinをつける必要はないらしい。(つけなくても一緒の挙動らしい)
参考
現場Rails
https://railsguides.jp/initialization.html
https://qiita.com/d0ne1s/items/fa2dafcee02e963fe997
https://github.com/rbenv/rbenv/wiki/Understanding-binstubs
https://techracho.bpsinc.jp/hachi8833/2016_08_24/25037
https://qiita.com/jnchito/items/c5a0848144203dce6e26
環境構築系学び
学び
シェルをbashに変更
echo $SHELL
で現在のシェル確認
chsh -s /bin/bash
で切り替え
これだとrbenvとnodenvのパスが通ってないので、vi ~/.bashrc
をして以下のように記述
export PATH="$HOME/.rbenv/bin:$PATH" eval "$(rbenv init - bash)" export PATH="$HOME/.nodenv/bin:$PATH" eval "$(nodenv init - bash)"
これでsource ~/.bashrc
すれば、rbenvとnodenvを使ってバージョンが変更できるようになる
Rubyの場合はrbenv local ○○
Nodeの場合はnodenv local ○○
で変更可能
Redis
「REmote DIctionary Server」のこと
NoSQL
インメモリなので高速
bundle install --path vendor/bundle
vendor/bundle以下にgemがインストールされる
gemをアプリケーションごとに管理できるため、バージョン違いによって起こる問題を解決できる
.gitignoreに設定していないとgitに大量に変更履歴が残ってしまうため注意
webpack
「JavaScript」「CSS」「画像やフォント」といった静的アセットを管理できる
より新しいJavaScriptツールやNPMパッケージとの統合に優れており、より多くのものを統合できる
参考URL
Macのターミナル(シェル)でbashやzsh を切り替える方法 | Hirooooo’s Labo
単純なアソシエーションと第3のモデルを利用したアソシエーション
何をまとめたいか
本投稿は単純なアソシエーションとブックマーク機能やお気に入り機能などを作れるような第3のモデルを利用したアソシエーションについてまとめていきます。
まだまだ知識浅薄であるため間違いがあったらご教示いただけると幸いです。
前提
猫型ロボット(nekogata_robot)は道具(item)を持っています。
また猫型ロボットは道具の保管方法としてポケット(pocket)を使用している時もあります。
それに伴い、モデルはnekogata_robot
・item
・pocket
にて考えていきます。それぞれ
$ rails g model Nekogata_robot name:string
$ rails g model Item nekogata_robot:references name:string
#1
$ rails g model pocket nekogata_robot:references item:references
#2
でモデルを作っておきます#1と#2は後から触れていきますがアソシエーションにおいて非常に重要です。
キホン!
様々な関連付けがありますが、まずはキホン的なものから。
猫型ロボット(nekogata_robot)は道具(item)を持っているためアソシエーションが成り立ちます。
nekogata_robotモデルとitemモデルを使用してアソシエーションを行なっていきます。
まず外部キー制約を考慮してitemモデルを作っていきます。
(既にnekogata_robotモデルは作成されている前提)
$ rails g model Item nekogata_robot:references
を行うと…
class CreateItems < ActiveRecord::Migration[6.1] def change create_table :items do |t| t.references :nekogata_robot, null: false, foreign_key: true t.string :name t.timestamps end end end
というマイグレーションファイルができます。これで$ rails db:migrate
をすると外部キーnekogata_robot_id
がカラムとして追加されます。(もちろんname
も追加されます)
これによってnekogata_robotモデルのid
(主キー)とitemモデルのnekogata_robot_id
(外部キー)によってデータベースにおける関連付けがなされます。
次にアソシエーションの関係をコードに書いていきます。
「一匹の猫型ロボットがたくさんの道具を持っている」
つまりnekogata_robotモデルに対してitemモデルは「1対多」の関係。
models/nekogata_robot.rb
has_many :items
models/item.rb
belongs_to :nekogata_robot, dependent: :destroy
猫型ロボットが壊れてしまったら道具の保有者がいなくなるので、そうした際は保有していた道具ごと削除する必要があります。
そのような場合にdependent: :destroy
は親モデルに連動して削除されるという機能をもたらします。
こうしてとりあえずのアソシエーションが完成したわけですが、実際に使用する際には
nekogata_robot.items.name
(猫型ロボットの持っている道具の名前を探す)
items.nekogata_robot.name
(道具を持っている猫型ロボットの名前を探す)
といった呼び出し方ができます。
以上がアソシエーションの基本です。
第3のモデルを利用したアソシエーション
ただこの猫型ロボットが持っている道具は単純に家に保管しているかもしれないですが、持ち運びをする場合にはポケットに保管していつでも道具を使えるようにしているかもしれないですよね?
また、猫型ロボットは一匹だけではなく、他にもたくさんの種類がいるかもしれないですよね?
すなわち以下の図のような関係をどのようにアソシエーションするかということです。
この「多対多」の考え方についてもアソシエーションによって関連づけをすることができます。
「猫型ロボットはポケットに道具を持っている」
「道具は猫型ロボットのポケットに収納されている」
すなわちnekogata_robotモデルとitemモデルの間には「pocketモデル」があるのでこれをhas_many :through
を使って関連づけをしていきます。
(この章の表題の第3のモデルとはpocketモデルのことだったのです!)
pocketモデルを作成するためには…
$ rails g model Pocket nekogata_robot:references item:references
を行います。
class CreatePockets < ActiveRecord::Migration[6.1] def change create_table :pockets do |t| t.references :nekogata_robot, null: false, foreign_key: true t.references :item, null: false, foreign_key: true t.timestamps end end end
というマイグレーションファイルができるので、例の如く$ rails db:migrate
をします。
するとnekogata_robot_id
カラムとitem_id
カラムが作成されます。
このpocketモデル内のnekogata_robot_id
にnekogata_robotモデルのid(猫型ロボットを特定するid)、
item_idにitemモデルのid
(道具を特定するid)を入れた状態でcreate
などをすることで保存していくと、データベースのpocketモデルにどの猫型ロボットがどの道具をポケットに収納しているのかというデータが保管されます。
同様に第3のモデルを考慮した際のコードも追加していきます。それぞれ
models/nekogata_robot.rb
has_many :pockets, dependent: :destroy has_many :pocket_items_boards, through: :pockets, source: :item
models/item.rb
has_many :pockets, dependent: :destroy has_many :pocket_items_boards, through: :pockets, source: :item
models/pocket.rb
belongs_to :nekogata_robot belongs_to :items
となります。上2つは全く同じコードです。
has_many :pockets, dependent: :destroy
当然アソシエーションを作るためにこの記述は必要となり、猫型ロボットか道具のいずれかが消えてしまえばポケットは存在する意味がないので消すべきです。
ただこの記述だけだと、それぞれがpocketメソッドとアソシエーションを結んでいるが、第3のモデルを使ったアソシエーションは依然使うことができない状態です。
そして次の記述が今回のポイント!
has_many :pocket_items_boards, through: :pockets, source: :item
2つ重要な要素があるのでそれぞれ確認をしていきます。
①through: :pockets
第3のモデルであるpocketsモデルを通じてそれぞれアソシエーションを組む際にはこの記述が必要不可欠です。この記述によって以下のようなコードでポケットを絡めたデータの呼び出しが可能になります。
nekogata_robot.pocket_items.name
(猫型ロボットがポケットに収納している道具の名前を探す)
ただこれだけでは物足りないと思います。安心してください、まだ特殊能力が付与されてます!
それがcollection << (object, …)
というメソッド!
Railsガイドには以下のような説明があります。
collection<<
メソッドは、1つ以上のオブジェクトをコレクションに追加します。このとき、追加されるオブジェクトの外部キーは、呼び出し側モデルの主キーに設定されます。
Railsガイドだけ見てもわかりにくいので実際に使ってみるとわかりやすいです。
models/nekogata_robot.rb
def pocket_create(item) pocket_items << item end
このようなメソッドを作成し、コントローラでnekogata_robot
とitem
をそれぞれ定義してあげた上で…
nekogata_robot.pocket_items(item)
のようなコードを使えば、レシーバのnekogata_robotよりnekogata_robot_id
が、引数のitemよりitem_id
がそれぞれ値が入力されてpocketモデルに新しいデータが作り出されます。これは
pocekt.create(nekogata_robot: params[:nekogata_robot], item: params[:item])
を行っていることと等しいため、コードの省略に貢献するでしょう!
②has_many :pocket_items, ~ source: :items
source
は基本的にアソシエーションを行う際に使います。
具体的にいうとsource
では実際にthrough
で指定したモデルを通じて関連づけをされる小モデルが指定されます。
なのでここではpocketモデルを通じて関連づけをされる子モデルitemモデルが入ります。なお複数形なので注意しましょう。
そして結論なのですが、has_many :pocket_items
ではsource: :items
で指定したitems
の代わりに、実際に使用する際にはpocket_items
を使うようにするという言い換えを定義しています。
なぜこんなことする必要があるのでしょうか?
それはこの言い換えを行わないとitemsが重複するからです。
キホン!でも説明したように、既にnekogata_robotと単純なアソシエーション関係にあるため…
nekogata_robot.items.name
(猫型ロボットの持っている道具の名前を探す)
のような使い方をされていました。
そして今またここでitemsを定義してしまうと、itemsは単純なアソシエーションによるものなのか?はたまた第三者のモデルを使ったアソシエーションによるものなのか?
2つの意味を持ってしまうため訳が分からなくなります。
そういった事態を避けるためにこのsource
を使用しています。なのでthrough
を使ったアソシエーションではsource
は非常に重要な意味を持つのです。
結論
単純なアソシエーションなら
has_many :〇〇
とbelongs_to :〇〇
第3のモデルを使う場合は単純なアソシエーションに加えて
has_many :〇〇, through: :〇〇, source: :〇〇
を書いてあげればOK!
なお今回の事例ではド〇えもんのポケットを例にして記入したため、22世紀まではこの機能を実装することはまずあり得ないと思います。
実際にはブックマーク機能やお気に入り機能を作る際に非常に役に立つっぽいです!
参考
https://qiita.com/imotan/items/036ceffb79e294d8a063
https://qiita.com/tomoharutt/items/e548186c763079327ed1#through
https://railsguides.jp/association_basics.html#has-many%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89-collection
自己紹介・ブログの指針
自己紹介
2021年5月末をもって以前在籍していた会社を退職し、現在フルコミットでプログラミング学習に専念しています!
ブログの指針
学習を進めていく中で気になったこと、つまづいたこと、よくよく考えてみたら意味が分かっていないことなどを深く追求し、簡潔にまとめていきたいと思っています。
まとめていくことでアウトプットをしていき、知識の拡充に努めていきます!
※追記
ブログの指針変更! - Tanaka on Rails
で指針を変更しました!
ちなみに…
普段の学習の記録をTwitterで発信しています!
よかったらフォローして監視をしてください😁↓