小ネタ
紹介サイト
いいところ
「コンテナ」「データベース」など、ある程度ジャンルに分かれて資料がおいてあるので興味のあるものをつまみ食いしたいときに便利
小ネタ
「コンテナ」「データベース」など、ある程度ジャンルに分かれて資料がおいてあるので興味のあるものをつまみ食いしたいときに便利
actionに対しての実行なのでそのとおりといえばそのとおりなんですが備忘として。
$ bin/rails --version Rails 6.0.4.1
以下のように必ず出力してほしいロギングを after_action
に設定し、特定の条件下でリダイレクトを行うようなケース
class RedirectTestsController < ApplicationController before_action :redirect_check, only: :show after_action :after_logging def index render json: { path: "index" } end def show render json: { id: params[:id] } end private def redirect_check if params[:id].to_i == 10 logger.info("***** redirect *****") redirect_to "/redirect_tests/" end end def after_logging logger.info("***** must after_logging! time: #{Time.zone.now} *****") end end
route.rbは以下
Rails.application.routes.draw do resources :redirect_tests end
上記のコードで http://localhost:3000/redirect_tests/1
にアクセスすると以下のようなログが出る。
Started GET "/redirect_tests/1" for ::1 at 2022-04-23 22:46:31 +0900 Processing by RedirectTestsController#show as HTML Parameters: {"id"=>"1"} ***** must after_logging! time: 2022-04-23 13:46:31 UTC ***** Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 335)
そして http://localhost:3000/redirect_tests/10
にアクセスすると、以下のようなログが出る
Started GET "/redirect_tests/10" for ::1 at 2022-04-23 22:48:05 +0900 Processing by RedirectTestsController#show as HTML Parameters: {"id"=>"10"} ***** redirect ***** Redirected to http://localhost:3000/redirect_tests/ Filter chain halted as :redirect_check rendered or redirected Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 308) Started GET "/redirect_tests/" for ::1 at 2022-04-23 22:48:05 +0900 Processing by RedirectTestsController#index as HTML ***** must after_logging! time: 2022-04-23 13:48:05 UTC ***** Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 317)
上記のようにbefore_actionでredirect処理が入ると、after_actionが実行されることがない。原理としては明確でactionの処理を実行することなく終わるため、actionが終わったあとに呼び出す after_action
が実行されない。
もちろんaround_actioのaction実行後の処理も呼び出されない。
いくつか方法論はありますが、before_actionとafter_actionの使い方をなるべく踏襲する形だと「レンダリング処理をコールバックでやるのを避ける」というのがあるので、今回はそちらを改善案として紹介します。
before_actionでリダイレクト処理を挟むとactionに到達する前に違うURLに行ってしまうので、遷移を挟む処理はbefore_actionでさせないようにする
class RedirectTestsController < ApplicationController before_action :redirect_check, only: :show after_action :after_logging def index render json: { path: "index" } end def show redirect_to "/redirect_tests/" and return if @redirect_flag render json: { id: params[:id] } end private def redirect_check @redirect_flag = false if params[:id].to_i == 10 logger.info("***** redirect flag on *****") @redirect_flag = true end end def after_logging logger.info("***** must after_logging! time: #{Time.zone.now} *****") end end
このやり方で http://localhost:3000/redirect_tests/10
にアクセスすると、以下のようなログが出て、ロギングがリダイレクト時にもちゃんとでる。
Started GET "/redirect_tests/10" for ::1 at 2022-04-23 22:58:14 +0900 (0.1ms) SELECT sqlite_version(*) Processing by RedirectTestsController#show as HTML Parameters: {"id"=>"10"} ***** redirect flag on ***** Redirected to http://localhost:3000/redirect_tests/ ***** must after_logging! time: 2022-04-23 13:58:14 UTC ***** Completed 302 Found in 1ms (ActiveRecord: 0.0ms | Allocations: 512) Started GET "/redirect_tests/" for ::1 at 2022-04-23 22:58:14 +0900 Processing by RedirectTestsController#index as HTML ***** must after_logging! time: 2022-04-23 13:58:14 UTC ***** Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 336)
自分なりの判断基準を整理したものです。
リーダブルコードには以下のような文章がある。
ぼくたちの経験からすると、プロジェクト固有の省略形はダメだ。新しくプロジェクトに参加した人は、暗号みたいに見えて怖いと思うだろう。しばらくすると、それを書いた人ですら暗号みたいで怖いと思うようになる。 新しいチームメイトはその名前の意味を理解できるだろうか? 理解できるなら問題ない。 プログラマは、evaluationの代わりにevalを使う。documentの代わりにdocを使う。stringの代わりにstrを使う。だから、新しいチームメイトもFormatStr()の意味は理解できる。 - リーダブルコード 2章 名前に情報を埋め込む 頭文字と省略形
このように「プロジェクト固有の略語は避けるべき」ということと「一般的に知れ渡っている略語なら良い」ということが書かれている。
リーダブルコードでは「プログラマは、evaluationの代わりにevalを使う。documentの代わりにdocを使う。stringの代わりにstrを使う。だから、新しいチームメイトもFormatStr()の意味は理解できる。」とありその中で「プログラマは」かなり大きめの主語で書かれているが、ここではプログラマがドキュメントを読む上で読み違えのないような略語を指すと思われる。例えばある程度の量のドキュメントやソースコードに接してきたプログラマは str
を stranger
とは誤読しないし、 var
を variety
と勘違いすることは少ないと思われる。
ただ、「conn
は connection
だ」のような言葉のマッピングは経験値で培われるもので、網羅的な情報があるわけでもなく、コンテキストによっては全く知る機会がないこともあるので、前提として「知らない人がいるかもしれない」という心持ちでコードレビューなどには望んだほうが良いと思われる。
一般的な略語であれば問題ないかと思われるが、例外として一般的な略語でも誤読が誘発されるものは避けるべきだと考える。
例えばプログラムの処理内容として「バラエティー番組の種類を選択させたい」というような内容を記述するときに variety
と variation
という単語が登場する。そのときに一時的な変数名などに var
を使うと、コードの作り方によっては「もしかしてバラエティー番組のことを指しているのか?」といらぬ懸念を抱かせてしまうので、このような状況下においては略語を避けて正しい言葉を当て込むほうがよいケースもあると思われる。
前提が「一般的に知れ渡っているものなら略語でも大丈夫」としたいところだが、誤読を誘発するようなものなら避けるべきなので、何も考えない方向にいくなら「略語は原則使わない」だがそれも窮屈すぎる場面があると思われる。
そのため、やはりどの程度で抑えるかはそのコードに関わる人たちの認識次第なので、リーダブルコードの一節を起点に認識合わせをしてチームとしてどうあるべきかの方向性を話をすると良いのだと思います。
当たり前の話なんだけど、暗黙の仕様の様子なので結果をまとめる
2022年現在ではHTML Living Standardで、faviconの指定は <link rel="icon">
で指定できるようになっている(参考:faviconの仕様はHTML5から標準化されている - コード日進月歩)
そのためブラウザに記述があればその指定されているパスのデータを取得する動作をする。
ただし、指定がない場合は /
配下にある favicon.ico
を探し、ファイルがあればそれを使用する。これはfaviconの仕様の始祖であるIEがそういう動きだったことに由来すると思われる。(一種のデファクトスタンダード)
詳しくは英語版のwikipediaにてまとめられているのでそちらを参照のこと。
前項で紹介したwikipediaにも記載があるが、多くのモダンブラウザでは「タブバー」もしくは「アドレスバー」にfaviconを出す仕様となっているので、ページを表示する場合にはほぼ確実にfaviconを取得する。そのため多くのブラウザでは閲覧するページに<link rel="icon">
がない場合、次点として /favicon.ico
にアクセスし表示できるデータがないかを探していく
この場合気をつけないといけないのは「最後にアクセスしたページ」が favicon.ico
になりうるということ。
昨今のWebアプリケーションは画像のアセットが別のドメインにあったりすることが多いので大体ページのgetリクエスト以降はアプリケーションサーバにアクセスすることが少なくなったので「最後にgetのあったリクエストを最後に閲覧したページとしてみなす」としても問題なく挙動してしまうシーンはあるが、このfavicon.icoが未指定の場合はfavicon.icoが最終アクセスページとして認識されてしまう可能性がある。
そもそも論Webブラウザの挙動を認識していれば最後にアクセスしたページ = 最後にgetリクエストがあったページという関連付けが成立しないことはわかるが、認識違いを起こすこともあるので気をつけたほうがいい。
developmentでは見れたのに、productionじゃ見れないのはなぜ…となるときに見直す設定
$ bin/rails -v Rails 6.0.4.1
/public配下のファイルが、RAILS_ENVがdevelopmentだと見れて、productionのときに見れないときに考える設定
public/ディレクトリ内の静的アセットを配信するかどうかを指定します。デフォルトではtrueが設定されますが、production環境ではアプリケーションを実行するNginxやApacheなどのサーバーが静的アセットを扱う必要があるので、falseに設定されます。 - Rails アプリケーションを設定する - Railsガイド - 3.1.35 config.public_file_server.enabled
ソースコード上も初期値はtrue
デフォルトのRailsであれば config/environments
のRAILS_ENV別の設定
productionに関しては以下のようになっている
# Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
なぜ消えるのか、という話。
https://bugs.chromium.org/p/chromium/issues/detail?id=883038#c114
原文を転載すると以下
The Chrome team values the simplicity, usability, and security of UI surfaces. To make URLs easier to read and understand, and to remove distractions from the registrable domain, we will hide URL components that are irrelevant to most Chrome users. We plan to hide “https” scheme and special-case subdomain “www” in Chrome omnibox on desktop and Android in M76.
Google翻訳を駆使して和訳すると以下
Chromeチームは、UI surfacesのシンプルさ、使いやすさ、セキュリティを高く評価しています。 URLを読みやすく理解しやすくし、登録可能なドメインから気を散らすものを取り除くために、ほとんどのChromeユーザーに関係のないURLコンポーネントを非表示にします。 デスクトップのChromeオムニボックスとM76のAndroidで「https」スキームと特殊なサブドメイン「www」を非表示にする予定です。
ということで、「https」などのURIスキーム部と「www」というサブドメインはユーザのために不要な情報なため消したという判断。
Version2からルールが変更になったので、そもそもどういう挙動か調べる
$ docker-compose --version Docker Compose version v2.3.3
{{プロジェクト名}}-{{サービス名}}-{{インデックス番号}}
となる。COMPOSE_PROJECT_NAME
の環境変数が使われるCOMPOSE_PROJECT_NAME
は格別指定がない場合は起動ディレクトリの文字列が設定されるデフォルトのコンテナ名は以下のロジックで書かれている
func getContainerName(projectName string, service types.ServiceConfig, number int) string { name := strings.Join([]string{projectName, service.Name, strconv.Itoa(number)}, Separator) if service.ContainerName != "" { name = service.ContainerName } return name }
from https://github.com/docker/compose/blob/v2/pkg/compose/convergence.go
明示的に service.ContainerName
があればそれが入るが、ない場合は Separator
で「プロジェクト名」「サービス名」「引数の番号」となる。このとき引数の番号は1から自動的に採番されるようになっている。
プロジェクト名は docker-compose -p
で指定できるもの。ヘルプでは以下のような記述がある。
-p, --project-name NAME Specify an alternate project name (default: directory name)
ディレクトリ名がデフォルトになるとのことだが、これは環境変数COMPOSE_PROJECT_NAME
との兼ね合いで設定されているもので、以下のような説明が公式ドキュメントにある。
この変数を設定するのは任意です。 変数を設定しなかった場合 COMPOSE_PROJECT_NAME のデフォルトは、プロジェクトディレクトリの basename となります。 コマンドラインオプション の -p も参照してください。 - Compose CLI 環境変数 — Docker-docs-ja 19.03 ドキュメント
指定したい場合はドキュメントにあるとおり container-name
を使うと指定できる。ただし重複したコンテナ名があると立ち上がらないので注意が必要。
container_name: sukina-container-mei
デフォルトのコンテナ名だが、昔は区切りが -
ではなく _
であったが、docker-composeのversinが2になるときに変更になっている。
これはhostnameとしてコンテナ名が使われるため、hostnameは _
を許容していないのでhostnameとして正しくつかえるようにするための変更だった様子。