コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Railsで最上位までExceptionが抜けた場合にRails側でハンドリングしてくれるエラーを追加したい場合はconfigに設定を追記する

ActiveRecord::RecordNotFoundをraiseしたときに404になるときに静的な404ページ出しているのでそれをそのまま真似て他のエラーでもキャッチしてくれないかな」という悩みを持つ人向け

検証したバージョン

$ bin/rails -v
Rails 7.0.6

前提としての動きのメカニズム

  • ActionDispatch::ExceptionWrapper.rescue_responsesにExceptionと対応するエラーのシンボルがある
  • Rack::Utils.status_codeを使ってシンボルを数値に変換
  • 変換した値を使って /public/{{ステータスコード数値}}.html あるいは /public/{{ステータスコード数値}}.{{i18nのロケール文字列}}.html の静的ファイルを読み取り表示。

詳しい挙動をトレースしたものは以下の記事に順を追って説明されているので参照のこと。

Railsのミドルウェアのエラーハンドリング

独自のエラーでも表示をしてもらうには

たとえば以下のようなエラークラスを作って、このエラーをキャッチした場合は404を出したいとする。

module OriginalException
  class HyperAccident < StandardError

  end
end

その場合は環境ごとのconfigに当該エラーをキャッチした場合の設定を追記してあげる。

Rails.application.configure do
  ### 中略 ###
  config.action_dispatch.rescue_responses = {
    # keyは対象となるException、valueに設定するのはHTTPステータスコードのシンボル。
    "OriginalException::HyperAccident" => :not_found
  }
end

上記のように記載してあげれば、404と同じ静的なHTMLを表示してくれる。例えば以下の場合 /test/0 でアクセスするとpublic配下に配置した404.htmlを表示する

class TestController < ApplicationController
  def show
    raise ::OriginalException::HyperAccident if params[:id] == "0"
    render json: {test: params}
  end
end

独自のviewや処理を加えたい場合は rescue_from を活用したほうがいいがそちらは関連リンク参照のこと。

関連リンク

『DESIGNING CONNECTED CONTENT』を読み終わったよメモ

読んだ本

DESIGNING CONNECTED CONTENT | ボーンデジタル

読むきっかけ

弁護士ドットコムさんが読書会をやっているということで気になり購入しました。

情報設計をもっと身近に〜DCC勉強会を主催して得た学びとチームの変化〜 - 弁護士ドットコム株式会社 Creators’ blog

読後の所感

Create Once Publish Everywhere (COPE)

この本を通して伝えられているのは、「Create Once Publish Everywhere(COPE)」というアプローチに基づいたWebプロダクトのデザイン方法です。COPEの考え方は、一度作成したコンテンツを、ウェブページや音声デバイスなど、出力の形式に縛られずに再利用できるようにするアイデアです。この本では、どのようにして情報の構造を構築し、見た目や利用方法に関係なく利用できるデータを作成するかについて、「IAサミット」というウェブサイトをベースに紹介しています。

ドメインに向き合う具体のアプローチ

監訳者の前書きにも触れられているように、この本はエリック・エヴァンスのドメイン駆動設計(DDD)の影響を受けており、DDDに詳しい人には「ドメイン理解を深める」というおなじみの話題が書籍の早い段階で登場します。また、ドメインの理解の方法も具体的に書かれており、『主題領域の調査』のパートではどのようにドメインの専門家にインタビューするといいかなどの内容があり、エリック・エヴァンスの本ではあまり語られていない専門家との対話に関しての部分に関して理解しやすい形で紹介されています。

非エンジニアでもデータ設計がわかりやすく紹介

ドメインの理解が進んだ後、具体的なデータ構造の設計方法が具体例を交えて説明されています。この本はエンジニア以外の読者を対象としているため、データ間の関係性や設計プロセスがわかりやすく説明されています。非エンジニアの方々にとって、エンジニアが通常行うデータ設計の理解を深める手助けになると思われます。また、エンジニアにとってもデータ設計の流れを再確認する機会となるかもしれません。

構造化データを維持することの難しさ

本書の最後の章である「未来は待ってくれない」では、構造化データとコンテンツの維持が直面する障壁や難しさについて議論され、未来への展望が語られています。情報が効果的に構造化されると再利用が容易になることは明らかではあるが、ビジネス要件やチームメンバーの変動によって、その維持が難しくなるケースが事例を通じて示されています。この章に至るまでに色々と試行錯誤して「IAサミット」のウェブサイトを良くしようと語られていた後に、この章で現実をぶつけられるので色々と思うところが多かったです。

DDDを知らない人の入り口としてもオススメ

ウェブ上でコンテンツを読んでもらったり見てもらったりするサイトを作る人には「自分が扱うサイトのコンテンツの構造はこれが最適なのか、本質的なものなのか」ということを考えるきっかけになる一冊であるかなと思っています。また、元の考え方がDDDから連なるものなので、DDDを知らない人がドメイン駆動で何かウェブサービスを作るときに読んでもらえるとよいのでは思える本でもありました。

関連リンク

Railsのschema.rbを手動で更新するときは db:schema:dump で生成される

migrateして更新されずあれこれ探していたので備忘として

環境

$ bin/rails -v
Rails 7.0.6

実行コマンド

$ bin/rails db:schema:dump

rakeとしてはこのあたりで、実装としては このあたり

動きとしての補足

通常、Railsガイドでも言及されている通りdb:migrateをすればセットで実行されるようになっている。

しかしながら、config.active_record.dump_schema_after_migration を falseにすると実行されないようになるので、もし更新されない場合はこちらを確認するとよい

関連リンク

制約理論を振り返るときに見たいスライド『制約理論(TOC)入門』

頭を整理したいときにスッと出せるように記録として

資料スライド

speakerdeck.com

みどころ

かなり端的に制約理論がまとまっており、このスライドを順に追うことで理解ができます。また復習としても使えるもので、誰かにレクチャーする際の資料としても使い勝手がよい資料になっています。また後半戦はシステムの話にスポットを当てているので事例資料としても読みやすい物となっています。

関連リンク

Railsのconfigのgemでは、環境ごとのymlに分けた値はdeep mergeされている

当たり前なんですけど、部分的に切り取ると違和感があるので言葉でまとめる

環境

config (4.2.1)

gemそのもののリポジトリは以下 rubyconfig/config: Easiest way to add multi-environment yaml settings to Rails, Sinatra, Pandrino and other Ruby projects.

上書き挙動について

configのgemは公式のREADMEにも記載がある通り、config/settings.yml を起点に環境名のymlでoverrideしていく。

具体例

たとえば以下のようにconfig/settings.ymlを書いたとする

default_user_data:
  id: example_default_user
  email: default_example@example.com
  max_eat_fruits_count:
    orange: 5
    melon: 1
    banana: 4
  favorite_sports:
    - baseball
    - soccer

そして、config/settings/development.yml を以下のように記述する。

default_user_data:
  id: example_user
  email: example@example.com
  max_eat_fruits_count:
    orange: 10
    apple: 2
    banana: 5
  favorite_sports:
    - basketball
    - soccer

この場合、config/settings/development.yml の設定が上書きされるので、RAILS_ENVがdevelopmentの場合、元々のconfig/settings.ymlにも存在するキーの値は上書きされる。

pp Settings.default_user_data.id
"example_user"

またArrayもあとがちとなる。

pp Settings.default_user_data.favorite_sports
["basketball", "soccer"]

このように default_user_data 起点で考えると、idemailfavorite_sports も上書きになっているので、 max_eat_fruits_count も上書きされるように見えるがそうはならない

pp Settings.default_user_data.max_eat_fruits_count.each { |key, value| pp "#{key} => #{value}" }
"orange => 10"
"melon => 1"
"banana => 5"
"apple => 2"

(よくよく考えれば当たり前だが)これはyml全体がhashなので、上書きされるとした場合に機能として成立しなくなるのでこのような挙動となる。

mergeされたくないHashがある場合はarrayで代替するしかない

原則Hash的な記法で記述をするとmergeされてしまうし、それを防ぐと全滝的に上書きする仕組みが機能しない。そのためもし「Hash的に扱いたいが、特定階層以下はmergeしないでほしい」という場合は苦肉の策としてarrayとHashを組み合わせるなどの方法を取るしかない。

たとえば以下のようにconfig/settings.ymlを書いたとする

default_user_data:
  max_eat_fruits_count:
    - orange: 5
    - melon: 1
    - banana: 4
default_user_data:
  max_eat_fruits_count:
    - orange: 10
    - apple: 2
    - banana: 5

このようにしてやればArrayなので上書きされる

pp Settings.default_user_data.max_eat_fruits_count.each { |hash_obj| hash_obj.each{|key,value| pp "#{key} => #{value}"  }}
"orange => 10"
"apple => 2"
"banana => 5"

そして以下のように取得すればHashとして扱うことも可能となる

result =  {}.merge(*Settings.default_user_data.max_eat_fruits_count)
pp result
{:orange=>10, :apple=>2, :banana=>5}

ただかなり無理やりなので、マージを避けなければいけない値がある場合は管理手法を見直したほうが良い

関連サイト

Mac上で録画した動画をDockerとffmpeg組み合わせてgifにする

GitHubのissueとかにサッと貼りたいけど、よくわからない画像編集ソフトはインストールしたくない人向けのコードスニペット

利用したdockerの環境

$ docker -v
Docker version 20.10.22, build 3a2c30b

コマンドの基本と例

$ docker run --rm -v {{ホスト側の変換したいファイルがあるディレクトリ}}:/target_dir {{ffmpegのコンテナ名}} -i /target_dir/{{変換させたい元ファイル名}} -r {{設定したいフレームレート}} /target_dir/{{変換後のgifファイル名}}

現在いるディレクトリの movie.movmovie.gif に変換したい場合の例は以下

$ docker run --rm -v $PWD:/target_dir jrottenberg/ffmpeg:4.1-alpine -i /target_dir/movie.mov -r 24 /target_dir/movie.gif

コマンドの詳細

docker側

dockerを起動する。

  • --rm はクリーンアップでコンテナの終了時にファイルシステムを削除する指定
  • --v はボリュームマウントの設定、「{{ホスト側のパス}}:{{コンテナ側のパス}}」となるように記述
    • なお例での $PWD は現在のディレクトリを指す。実行するディレクトリにファイルがない場合は $PWD/target_no_dir などの記述もできる

ffmpeg

  • -i は入力ソースの指定。当たり前だがコンテナ側のパスを指定する。
  • -r 切り出したい画像のフレームレート。低ければ低いほど容量は下がるので利用用途に応じて調整。

参考サイト

Railsでsymbol表記のhttp status codeを数値に変換するときにはRack::Utils.status_codeを使うと変換できる

Rails上で render status: :not_found とかやっているが、この :not_found404 はどこなのか、という小ネタ。

確認した環境

$ bin/rails -v
Rails 7.0.6

Railsステータスコードのシンボル

一覧はRailsガイドにある。

レイアウトとレンダリング-2.2.13.4 :statusオプション - Railsガイド

実装の元ネタはどこにあるかというとrack側にあり、 ::Rack::Utils::HTTP_STATUS_CODESにあり、ここに定義のある文字列を改変してシンボル化している。

簡単に変換したい場合

Rack::Utils.status_code を使うと変換ができる。

Rack::Utils.status_code(:gateway_timeout)
# => 504

ちなみにありえないシンボルを入れるとエラー( Unrecognized status code :hogehoge (ArgumentError) になるので、使う場合はエラーハンドリングをちゃんと考えること。なお、ステータスコードの数値をシンボルに変換するメソッドはない様子。

参考リンク