- 開発
週刊Railsウォッチ(20191105前編)Rails 6のデフォルト設定解説、DHHも消したいaccepts_nested_attributes_for、スライド『実践Railsアプリケーション設計』ほか
こんにちは、hachi8833です。今年の3連休は昨日のでおしまいだそうです。
実を言うと今年の祝日はもうだめです。
突然こんなこと言ってごめんね。
でも本当です。この週末から月曜にかけて
3連休が来ます。それが終わりの合図です。
3週間後に土曜日に潰される祝日が来るので
気をつけて。
それが過ぎたら、もう今年が終わるまで
祝日はありません。— usa (@unak) November 1, 2019
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
⚓お知らせ: 週刊Railsウォッチ「第16回公開つっつき会」(無料)
第16回目公開つっつき会は、来週11月14日(木)19:30〜にBPS会議スペースにて開催されます。今回は月初ではありませんのでご注意ください。
週刊Railsウォッチの記事にいち早く触れられるチャンス!発言・質問も自由です。引き続き皆さまのお気軽なご参加をお待ちしております🙇。
⚓Rails: 先週の改修(Rails公式ニュースより)
今週は平和に公式情報からです。
⚓Active Storage blobのパーマネントURLを公開可能に
- PR: Permanent URLs for Active Storage blobs by peterzhu2118 · Pull Request #36729 · rails/rails -- closeですが実際にはマージされています
blob向けのパーマネントURL。
configurations.yml
でサービスのキーにpublic: true | false
を設定することで、サービスのblobをpublicまたはprivateにできる。publicなサービスは常にパーマネントURLを返すようになる。
Blob#service_url
は非推奨になり、Blob#url
が推奨される。
changelogより
# activestorage/test/service/s3_public_service_test.rb
+# frozen_string_literal: true
+
+require "service/shared_service_tests"
+require "net/http"
+require "database/setup"
+if SERVICE_CONFIGURATIONS[:s3]
+ class ActiveStorage::Service::S3PublicServiceTest < ActiveSupport::TestCase
+ SERVICE = ActiveStorage::Service.configure(:s3_public, +SERVICE_CONFIGURATIONS)
+
+ include ActiveStorage::Service::SharedServiceTests
+
+ test "public URL generation" do
+ url = @service.url(@key, filename: +ActiveStorage::Filename.new("avatar.png"))
+
+ assert_match(/.*\.s3\.amazonaws\.com\/.*\/#{@key}/, url)
+
+ response = Net::HTTP.get_response(URI(url))
+ assert_equal "200", response.code
+ end
+ end
+else
+ puts "Skipping S3 Public Service tests because no S3 configuration was supplied"
+end
つっつきボイス:「issue #31419の、Active StorageのService APIからファイルへのアクセスも許可したいという流れで入ったPRだそうです」「ほほう😋」「パーマネントURLって何を指してるのかな?🤔」「#31419にいいね👍が48個もついてるのでみんな欲しがってるっぽい😆」
ActiveStorage::Service
の現時点のAPIではurl
メソッドでしかリンクを取得できず、返されるpublic URLはほとんどのサービスでは同じタイムフレーム内で期限切れになる。サービスからファイルオブジェクトにもアクセスできるfile
メソッド的なものがあれば、ファイルの公開方法をより柔軟にできて便利になると思われる。
#31419より大意
「#36729を見ると(ストレージ)プロバイダのpublic URLでは一般にファイル名をカスタマイズできないので、現状はpublic bucketとprivate bucketのディレクトリ構造が違ってしまっている: この修正ではconfigで設定すればS3やAzureやGCSで/キー/ファイル名
の固定URLで統一的にアップロードして後でそのURLでダウンロードできるようにする、という感じのようです🤔」「まだActive Storageちゃんと使ってないけど、あるとうれしい機能らしいということはわかった😆」
⚓has_many
のinverseが設定可能になった
この間取り上げた#34533の続きだそうです(ウォッチ20191021)が、#37413は取り上げてませんでした。
- PR: Add support for belongs_to to has_many inversing. by gmcgibbon · Pull Request #34533 · rails/rails
- PR: Don't run callbacks on has_many inverse add by gmcgibbon · Pull Request #37413 · rails/rails
# activerecord/lib/active_record/railtie.rb#L29
config.active_record.use_schema_cache_dump = true
config.active_record.maintain_test_schema = true
+ config.active_record.has_many_inversing = false
つっつきボイス:「先週はhas_many
関連が豊作でしたけど😆、#34533
で入ったhas_many
のinverseを利用できるようにするかどうかを設定で選べるようになったそうです(デフォルトはfalse)」「has_many
でinverseできるのが本来だけどbreaking changeになるから設定を増やしたのね☺️」
⚓inflectorが:zeitwerk
モードでオーバーライド可能になった
# activesupport/lib/active_support/dependencies/zeitwerk_integration.rb#L56
module Inflector
+ # Concurrent::Map is not needed. This is a private class, and overrides
+ # must be defined while the application boots.
+ @overrides = {}
- def self.camelize(basename, _abspath)
+ basename.camelize
+ @overrides[basename] || basename.camelize
+ end
+
+ def self.inflect(overrides)
+ @overrides.merge!(overrides)
+ end
end
つっつきボイス:「Active SupportのinflectorはRailsで名前の単数形複数形みたいな活用形(inflection)を制御するヤツですね☺️」「@overrides
というハッシュがあればオーバーライドできると」「特殊な活用形をここに入れられる感じですね😋」「basenameがあればよし、なければcamelize
すると」
「Railsガイドの更新↓を見るとautoloaderでこうやって活用形を定義できるとありますね」「html_parser
をHTMLParser
に変換するヤツわかる〜😆」「HtmlParser
だと違う感ありますね😆」「SslError
も違う感😆」「Html
は現実に使われちゃってるところもあったりするのでワンチャンありな気もしなくもないけど😆」「HTMLは大文字にしたいです〜😭」
以下のようにすることでActive Supportの活用形がグローバルに効く。アプリケーションによってはこれでもよいが、Active Supportでデフォルトのinflectorにオーバーライドのコレクションを渡してbasenameを個別に
camerize
することもできる。
ガイド更新分より大意
# guides/source/autoloading_and_reloading_constants.md#L289
# config/initializers/zeitwerk.rb
-inflector = Object.new
-def inflector.camelize(basename, _abspath)
- basename == "html_parser" ? "HTMLParser" : basename.camelize
-end
-
Rails.autoloaders.each do |autoloader|
- autoloader.inflector = inflector
+ autoloader.inflector.inflect(
+ "html_parser" => "HTMLParser",
+ "ssl_error" => "SSLError"
+ )
end
「inflectionってときどきinfection(感染)と間違えそうになります😆」
⚓ルーティングのマッパーでHTTPのOPTIONS
をサポート
# actionpack/lib/action_dispatch/routing/mapper.rb#L752
+ # Define a route that only recognizes HTTP OPTIONS.
+ # For supported arguments, see match[rdoc-ref:Base#match]
+ #
+ # options 'carrots', to: 'food#carrots'
+ def options(*args, &block)
+ map_method(:options, args, &block)
+ end
つっつきボイス:「何とHTTPのOPTIONS verbがルーティングマッパーで初めてサポートされたそうです」「あれ〜今までなかった?」「OPTIONSってそういえばあったわ😆」
curl -X OPTIONS http://example.org -i
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
developer.mozilla.orgより
「新機能にしてはテスト無しでズコっと入ってますね😆」「今更ですけどmapper.rbのコード↓めちゃ長い〜😇」「2300行😇」
「#37370のプルリク↓見ると、今まではmatch
を使わないと書けなかったのか」「シンタックスシュガーというか😳」「OPTIONS何に使うんだろう😆」「要るのかどうかは知らないけど😆」「クローラーとかで使いそうですけど、業務だとあまり使わないかな?」「とも言い切れなさそう😆」
# 同PRより
# before
match 'bar', to: 'foo#bar', via: :options
# after
options 'bar', to: 'foo#bar'
「ルーティングといえば、以前つっつきでmorimorihogeさんが『Railsのルーティングは組み合わさったときにどう動くのかがわからなくてつらい』って言ってましたね(ウォッチ20180406)」「ほんにそれ: ひとつひとつのAPIにはドキュメントがあるけど組み合わせたときがマジむずいし、しょうがないからルーティングを切ってはアクセスしてみて動いた〜とか動かない〜とかやってますし😭」
⚓番外: RailsはまだSameSite=None
パッチがマージされていない
つっつきボイス:「前回のウォッチのレビュー中に教わった情報で、cookieにSameSite=None
を設定していないサイトは来年2月からChromeでSameSite=Lax
とみなすぞということだそうです」「Laxって『ゆるい』ってことか😆」「Railsではそれに対応する2017年の#28297がまだマージされてないそうです😳」
参考: Chrome で SameSite=None
に関する Cookieについての警告が表示される | ラボラジアン
参考: CookieのSameSite属性 NoneとLaxの違い - Qiita
#28297の最新のコメントを見ると『現在のメンテナンスポリシーによるとこれが入るのは早くてRails 6.1で、バックポートはされないかも』とあります。
⚓Rails
なお、今週のRuby Weeklyの末尾のICYMIがなかなかよさそうなエントリでした。
つっつきボイス:「ICYMIを調べたら『In case you missed it』の略で『もしご存知なければ』という感じですね☺️」
「その中でこの記事↓はリードオンリーのRailsコンソールを使う方法の解説です」「productionのデータをぶっ壊さずにコンソール使いたいときはあるかも☺️」「dry run的な」「save
やめろぉぉみたいなことがなくなるのはよさそう😆」「ローカルでもリードオンリーコンソールをやりたいことはあったりしますね: 頑張って作ったテストデータをうっかり壊したくないときとか😋」
参考: How to Setup a Readonly Rails Console - DEV Community 👩💻👨💻
⚓Rails 6の新しいデフォルト設定の意味と、安全にコメント解除する方法(Ruby Weeklyより)
同記事より(長いのでRails.application.config.
は略しました):
action_view.default_enforce_utf8 = false
action_dispatch.use_cookies_with_metadata = true
action_dispatch.return_only_media_type_on_content_type = false
active_job.return_false_on_aborted_enqueue = true
active_storage.queues.analysis = :active_storage_analysis
active_storage.queues.purge = :active_storage_purge
active_storage.replace_on_assign_to_many = true
action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
active_record.collection_cache_versioning = true
config.autoloader = :zeitwerk
つっつきボイス:「この記事はRails 6で追加された新しい設定のいくつかを詳しく解説して、移行時に設定のコメントを安全に外す方法も書かれています」「おほ😍」
「バージョンアップのたびにconfigの項目って増えますよね😆」「それはしゃーない😆」「RailsのconfigについてはRailsガイド↓にもありますけど最小限しか書かれていないことが多いので😅」
「たとえばaction_dispatch.use_cookies_with_metadata = true
を有効にするとpurposeフィールドをcookieに追加してから署名・暗号化する、その代わり一度有効にしたらRails 5.xにダウングレードできなくなる、という具合」「へぇ〜😳」「引き返せない設定😇」
「action_dispatch.return_only_media_type_on_content_type = false
も長いですけど😆、有効にするとcontent_type
でmedia type以外の値(charset=utf-8
など)も含まれるようになる」「最近のcontent_type
周りの修正に関連してそう🤔(ウォッチ20190902)」
「active_job.return_false_on_aborted_enqueue = true
はActive Jobですね」「Active Jobでthrow(:abort)
できる↓って知らなかった〜😳」「そこの挙動を変えられるんですね」
# 同記事より
class MyJob < ApplicationJob
before_enqueue { |job| throw(:abort) if job.arguments.first }
def perform; end
end
job1 = MyJob.perform_later(false)
job2 = MyJob.perform_later(true)
「active_storage.queues.analysis = :active_storage_analysis
」「Active Storageで何か分析してくれるのかな?😆」「あ、画像のheight
やwidth
を取ってmini_magickで使ったりできるのか」
「きりがないのでこの辺で止めますけど、Railsガイドだけだとわからない情報があってよさそうですね😍」「configできれば触りたくないけど😢」「必要になったらこの記事を泣きながら読むことになるんでしょうね😆」「ありそう😆」「この記事翻訳したいです😋」
⚓Rails 6でビューヘルパーのimage_alt
が削除
たしかに最新のapi.rubyonrails.orgから消えています。
# api.rubyonrails.orgより
image_alt('rails.png')
# => Rails
image_alt('hyphenated-file-name.png')
# => Hyphenated file name
image_alt('underscored_file_name.png')
# => Underscored file name
つっつきボイス:「image_alt
ヘルパーがRails 6から消えたそうです」「そういえば最近は自分でaltを設定しないといけないことになってた気がするけどそれかな😎」「image_alt
がファイル名から適当に推測して生成するaltテキストがスクリーンリーダーなどでいろいろ具合がよくなかったそうです」「やはりaltぐらい自分で書けと」「書きたくないけど😆」
後で調べると、Rails 5.2でimage_alt
が非推奨になっていました↓。image_tag
からの呼び出しも削除されたそうです。
- PR: Do not generate default alt text for images by ckundo · Pull Request #30213 · rails/rails
- ガイド: Action View 6.2 非推奨 -- Ruby on Rails 5.2 リリースノート - Rails ガイド
⚓DHHも消したがっているaccepts_nested_attributes_for
- API:
accepts_nested_attributes_for
-- ActiveRecord::NestedAttributes::ClassMethods - PRコメント: Add form_with to unify form_tag/form_for. by kaspth · Pull Request #26976 · rails/rails
上はDiscourseのclean-railsで知りました↓。
つっつきボイス:「以前から評判のよろしくないaccepts_nested_attributes_for
ですけど(ウォッチ20180820)、少なくとも2016年の時点ではDHHも殺したいと思っていることを上で知りました😆」「これは殺していいと思う🙋♀️」「使ったことあるけど心底つらかった〜😇」「Discourseでjoker1007さんも滅びるべきと書いてますね」「自分もjoker1007さんに全面同意🙋♀️」
「DHHもコメントで『新しいAPIとして推奨すべきでない』『むしろコントローラで手動でやる方法を示すべき』と書いてますね」「わかる〜😂」
「joker1007さんのコメントでも言及されているけど、こういうのはむしろJSON構造から攻略するのがいいんじゃないかって自分も思いますし☺️」「なるほど!」「動的にフォームの項目を増やすんなら結局JavaScriptのお世話になりますし、そうやってJavaScript使ったのに結局素のフォームだったら意味ないので、素直にAPI叩けばええやんって思いますし😆」
⚓accepts_nested_attributes_for
はデモ用なのか?
「ここは自分の推測でしかないんですけど、accepts_nested_attributes_for
ってもしかすると『Railsなら15分でアプリを書けまっせドヤァ😎』みたいなデモ用なんじゃないかって今思いました」「あ〜何だかわかる気がします😳」「ほとんど何も書かなくてもよしなにやれるあたりとか、そういう用途だと有用なんですよ」「ところがそれを真に受けて業務で使うと途端に破綻するという🤣」「🤣」「モデルもビューも結構癒着しますし😇、これって単純に追加して保存できるだけなんじゃね?って」
「こんな例えが合ってるかどうかわかりませんけど、楽器のキーボードについているデモ演奏ボタン↓にちょっと似ているかもですね😆」「それそれっ🤣」「そのデモ演奏ボタンを本番のライブで無理やり使おうとしているみたいな😆」「デモ演奏だとテンポも変えられませんし😆」
「まあそういう感じのデモ機能って15年ぐらい前に流行りましたよね☺️」「ボタン一発でブログサイトを作れますとか😆」「そういうデモでhas_many周りを一気にやれるのを見せるのはとってもインパクトあるんですけど、実際には使えないという🤣」「deleteってどうすんの?みたいなレベルで既に悩む」「で建て増しを繰り返すうちに結局詰んだり😇」
「idがついてないとcreateだし、idがついていればupdateだし、deleteフラグが立ってればdestroyするし、というのを一見同時にやれそうな気がするんですよ: でも誰もコントロールできない😆」「スレッドセーフとかも大丈夫かどうかよくわからないし😅」「歴史調べてないのであくまで推測&印象😆」「自分一人しか使わない管理画面で、かつ重要じゃないデータを手軽に出したいみたいなユースケースならaccepts_nested_attributes_for
はまだワンチャンあるかなって思います☺️」
「なおaccepts_nested_attributes_for
はRails 2.3からあるそうです↓」「割と古くからあった気はします」「さすがに最初期からではなかった😆」
⚓Meetup for Rails engineersのスライド3つ
- イベント: Meetup for Rails engineers -メドピア×リンカーズ×Classi開発事例- - connpass
- Twitterハッシュタグ: #meetup_rails - Twitter検索 / Twitter
つっつきボイス:「こちらのイベントを見逃してて、終わってから気づきました😅」「3つは追いきれないので、とりあえず『実践Railsアプリケーション設計』のスライドを見てみましょうか😋」
Meetup for Rails engineers -メドピア×リンカーズ×Classi開発事例-
草分の登壇資料はこちらです!
「FeatureFlagを用いて新機能を安全にマージ&リリースする」https://t.co/ylNORmLMM7#メドピア #meetup_rails— メドピア株式会社(MedPeer, Inc.) (@medpeer_post) October 31, 2019
ER図が出来たら開発者同士で名付けさせてビジネス側にも名前を徹底する / “実践Railsアプリケーション設計 #meetup_rails / Practical Rails Application Design - Speaker Deck” https://t.co/XWHMJcknP3
— すてィーろ (@stilo) October 31, 2019
Meetup for Rails engineers -メドピア×リンカーズ×Classi開発事例-にて発表した資料です。https://t.co/NqLJY0oVYH
発表途中にMacが再起動してあせりました💦https://t.co/IcjFnALtas#meetup_rails #メドピア— takashi.miyahara@メドピア (@TakashiMiyahara) October 30, 2019
⚓『実践Railsアプリケーション設計』
つっつきではかなり盛り上がりましたが、記事にすると多すぎるので間引いています🙇。
「『実装とテストは資料が多いけど、設計の書籍は抽象的な内容が多い』と」「これホントにそう!外部設計と内部設計の本ってたいてい抽象論になっちゃう😭」「なるべく具体的な設計の過程を知りたいですよね」「ところが設計を具体的に書くと、今度は分量が増える割には価値が薄くなっちゃうという😇」「読んだ人にとっては自分の業務に合わないとかが続出しちゃうんですよ😢」「言語が違うだけでも大きく変わりますし」「設計論を具体的に書くと一般性が損なわれちゃうんですね😅」
「しかも本当に具体的な設計ってビジネス上の機密に直結しちゃうから、そういうものほど本にできない😆」「そうそう😆」
「このスライドでは以下に絞って話を進めていますね」
「要件から重要な名詞と動詞を抽出して、概念を固めたうえで関係をまとめる↓」「つまりエンティティに適切な名前を与える」「そこが超重要👍」「設計って実はものすごく日本語力を要求されるんですよ」「誰が見ても誤解しない名前をつけるのが大事」
「最近自分が設計するときは、いきなり英語名を付けないように注意してますね☺️」
「これが実際の名前か↓」「ReassociatedRequestだと受動態か完了形か迷っちゃうので、個人的にはReassociationRequestとしたい気がしますけど😆」「実際の業務を見ないとどっちが適切か判断難しいですね😅」「やっぱり名前むずい😭」
「このスライドいいですね👍」「ここに書ききれないぐらいいい話がいっぱい出ました😂」「こういうスライドを元に強い人が解説するのがよい気がしました😋」
⚓でかい画像を正しく扱う
つっつきボイス:「お馴染みEvil Martiansの記事で、Railsに限定せずにでかい画像を適切に扱う方法を解説しています」「こんな図も↓」「かなり長い記事...😅」
⚓TimeWithZoneクラス
つっつきボイス:「ベストマサフミさんの短い記事です」「:db
はto_time
で変換しないとUTCになっちゃうのか😳」
⚓その他Rails
RAILS_ENV=stagingは悪い文化、というのを書きたかったけど紙幅が足りない,、、、と思ったけど「ソフトウェア開発のデプロイメントパイプラインにおけるステージと、Railsの実行モード(RAILS_ENVが制御するのはこっち)は違う」で140文字で足りた。
— MOROHASHI Kyosuke (@moro) March 14, 2018
クラスの自動リロードなど不要なので、実行モードは production でいいかなと思います。あとは接続するデータストアの設定なんかはすべて環境変数なんかでまとめて扱うのがいいんじゃないかなと思います。12 factor~にあるような
— MOROHASHI Kyosuke (@moro) March 14, 2018
つっつきボイス:「RAILS_ENV=staging
はたしかに悪い文化!」「productionとstagingで環境を分ける意味ってあんまりなくて、stagingはデータが本物ならproductionになれるようにするのが正確ですね☺️」「でないとif staging
みたいなのができてだんだんつらくなるし」「挙句の果てにstagingはよくてもproductionでコケたりしますし😇」「そしてproductionはデプロイしないとどうなるかわかりません、になって本末転倒になると😆」
Rails向けモダンフロントエンド開発の本だって。ちょっと気になる〜。
Modern Front-End Development for Rails: Webpacker, Stimulus, and React by Noel Rappin | The Pragmatic Bookshelf https://t.co/aRm9wKSm58
— Junichi Ito (伊藤淳一) (@jnchito) October 30, 2019
つっつきボイス:「まだbetaだそうですが気になりますね😋」「Railsとフロントエンドってそんなに相性悪くないと自分は思うんですけどね☺️」「仲良くなれないという思い込みもあるのかも?」「たぶんね」「でもたぶん仲良くはなれない🤣」「🤣」
前編は以上です。
おたより発掘
週刊Railsウォッチ(20191105前編)Rails 6のデフォルト設定解説、DHHも消したいaccepts_nested_attributes_for、スライド『実践Railsアプリケーション設計』ほか https://t.co/Sv9xLdsCJ6
スライド伸びててびっくりしたんですが、TechRachoさんで紹介していただいたんですね……!
身に余る光栄です— expa / Shu OGAWARA (@expajp) November 5, 2019
こちらこそありがとうございます🙇。
Active StorageにパーマネントURLができたのかhttps://t.co/RUwHPtSGix
— KAMI (@kami_zh) November 5, 2019
バックナンバー(2019年度第4四半期)
週刊Railsウォッチ(20191029後編)Ruby 2.7.0-preview2、tapping_device gemとhumanize gem、平成Ruby会議ほか
- 20191028前編 RailsにSTI用メソッドsti_class_forとpolymorphic_class_forが追加、RuboCopを変更箇所だけにかけるgem、strftime書式生成サイトほか
- 20191021 Rails 6でhas_many関連の修正やSprockets 4.0対応、Shrine 3.0がリリース、Minitestスタイルガイドほか
- 20191015 スライド「Rails Performance issues and Solutions」を見る、dirtyに*_previously_was が追加、Sidekiq 6.0.1ほか
- 20191008後編 Ruby 2.7のInteger#[]でバイナリチェック、rubyzip gemは強力、13KBのJavaScriptゲームほか
- 20191001後編 RedisとRubyをつなぐredis-object gem、Fullstaq Rubyの新バージョン、COUNT(*)とCOUNT(1)の速度ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp Slackなど)です。