- 開発
週刊Railsウォッチ(20191007前編)Ruby 2.6.5でセキュリティ修正、Arel.sqlがstable APIに、Puma 4.2、RailsのDomain ObjectとService Objectほか
こんにちは、hachi8833です。そういえば今夜からノーベル賞発表が始まりますね。
Coming up: we'll soon be announcing the first of this year's Nobel Prizes.
Stay tuned to discover who has been awarded the 2019 Nobel Prize in Physiology or Medicine. We'll be breaking the news right here @nobelprize.#NobelPrize pic.twitter.com/WTsdghPg1Q
— The Nobel Prize (@NobelPrize) October 7, 2019
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
今回は第15回公開つっつき会からお送りします。お集まりいただきありがとうございました!🙇。
⚓臨時ニュース: Ruby 2.6.5などセキュリティ修正リリース
Ruby 2.6.5のインストールが完了。Ruby 2.5.7と2.4.9もリリースされていますね。脆弱性対応なので早めにアップデートしておく方が良さそうです。
Ruby 2.6.5 リリース https://t.co/Paz9I49WsE
— Junichi Ito (伊藤淳一) (@jnchito) October 3, 2019
- リリースノート: Ruby 2.6.5 リリース
- リリースノート: Ruby 2.5.7 リリース
- リリースノート: Ruby 2.4.8 リリース
ウォッチ20190925で取り上げた#16136の文字化け問題も2.6.5で修正されています。
⚓Rails: 先週の改修(Rails公式ニュースより)
⚓(master)stat(2)
の呼び出しを削減
File.file?
やその他の述語(メソッド)はパーミッションについて同じstat(2)の呼び出し結果を利用できる。
同PRより大意
つっつきボイス:「nobuさんのRailsコミットを初めて見たような気がします」「stat(2)
って何を指しているんでしたっけ?🤔」「man
コマンドで2 stat
とセクション番号を指定するということだと思います☺️」「そちらでしたか😅」「セクション2だからシステムコールですね↓」
参考: manコマンドについて詳しくまとめました 【Linuxコマンド集】
STAT(2) Linux Programmer's Manual STAT(2)
NAME
stat, fstat, lstat, fstatat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>
int fstatat(int dirfd, const char *pathname, struct stat *statbuf,
int flags);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
lstat():
/* glibc 2.19 and earlier */ _BSD_SOURCE
|| /* Since glibc 2.20 */ _DEFAULT_SOURCE
|| _XOPEN_SOURCE >= 500
|| /* Since glibc 2.10: */ _POSIX_C_SOURCE >= 200112L
fstatat():
Since glibc 2.10:
_POSIX_C_SOURCE >= 200809L
Before glibc 2.10:
_ATFILE_SOURCE
「manのセクション番号、6が『ゲームやデモ』ってなってますし😆」「セクション番号っていつまでたっても覚えられなくて😅」「自分も2がシステムコール、ぐらいしか覚えてませんけど😆」
参考: singleton method File.stat
(Ruby 2.6.0)
「rescue
でelse
って書けるんですね↓😳」「書いてもよかったはず」「必ず実行するときは何でしたっけ」「ensure
で〜す😆」「File.stat
はシステムコールのstat()
を呼んで返しているだけですね☺️」
# actionpack/lib/action_dispatch/middleware/static.rb#L84
def file_readable?(path)
- file_path = File.join(@root, path.b)
- File.file?(file_path) && File.readable?(file_path)
+ file_stat = File.stat(File.join(@root, path.b))
rescue SystemCallError
+ false
+ else
+ file_stat.file? && file_stat.readable?
end
# railties/lib/rails/commands/dbconsole/dbconsole_command.rb#L122
def find_cmd_and_exec(commands, *args) # :doc:
commands = Array(commands)
dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
commands = commands.map { |cmd| "#{cmd}#{ext}" }
end
full_path_command = nil
found = commands.detect do |cmd|
dirs_on_path.detect do |path|
full_path_command = File.join(path, cmd)
- File.file?(full_path_command) && File.executable?(full_path_command)
+ begin
+ stat = File.stat(full_path_command)
+ rescue SystemCallError
+ else
+ stat.file? && stat.executable?
+ end
end
end
⚓(master)serialize
メソッドでシンボルもstringにシリアライズするよう修正
model.some_string = :foo
model.save! # "foo" が永続化される
シンボルは永続化するときに上のようにstringにシリアライズされる。
このPRでは、シンボルをstringにシリアライズするImmutableStringクラスを更新して、ActiveModel::Attribute
がこのシリアライズメソッドを呼び出してchanged_in_place?
の戻り値を確定させる振る舞いと同じになるようにする。
この変更が行われる前は、以下のように"something"が変更されたと表示されていたが、変更後はcomment.something_change
がnilを返すようになる。
同PRより大意
comment = Comment.create! # (文字列の"something"フィールドがある)
# commentsテーブルかcomment.attributesの"something"フィールドで"anything"を永続化する
comment.update_column :something, :anything
comment.something # or comment.attributes
comment.something_change
# 上は["anything", "anything"]になる
# `to`と`from`の値なのに同じになってしまう
つっつきボイス:「シンボルをシリアライズするときにstringにするということらしい」「前はシンボルの場合にto_s
されていなかったと」
# activemodel/lib/active_model/type/immutable_string.rb#L10
def serialize(value)
case value
- when ::Numeric, ActiveSupport::Duration then value.to_s
+ when ::Numeric, ::Symbol, ActiveSupport::Duration then value.to_s
when true then "t"
when false then "f"
else super
end
end
⚓(master)ActionController::Base.log_at
を追加
ここからはcloseした6.0.1マイルストーンから見繕いました。
# 同PRより
# リクエストごとにログレベルを変える
class ApplicationController < ActionController::Base
log_at :debug, if: -> { cookies[:debug] }
end
つっつきボイス:「Base.log_at
でリクエストごとにログレベルを変えられるそうです」「ほほぉ〜😋」「うーん、こういうのって気持ちはわかるんだけど、消し忘れて惨事を招きそうな気がしないでもない😇」「同時実行制御あたりとの相性も気になるし」
# actionpack/lib/action_controller/metal/logging.rb
module ActionController
module Logging
extend ActiveSupport::Concern
module ClassMethods
def log_at(level, **options)
around_action ->(_, action) { logger.log_at(level, &action) }, **options
end
end
end
「使いみちとしては、うるさいログを黙らせるとかでしょうね☺️」「Authenticationコントローラのログはもう出さなくていいよ、とか😆」「惨事というのは、クライアントからcookieを仕込めるからですか?」「その辺ですね、中身を知っていればクライアントが『このリクエストだけログを出さないでくれ』みたいなのをやれる可能性があるといえばある😆」
⚓(master、6.0.1)RedisCacheStore
が最大クライアントコネクション数到達時に安全にfaliするよう修正
# activesupport/lib/active_support/cache/redis_cache_store.rb#L477
def failsafe(method, returning: nil)
yield
- rescue ::Redis::BaseConnectionError => e
+ rescue ::Redis::BaseError => e
handle_exception exception: e, method: method, returning: returning
returning
end
キャッシュに使っていたHerokuのRedisに関連して最近サービス中断の憂き目に遭った。Redisサーバーが最大クライアント数に達していた。Redis Cache Storeにはコネクションエラー時にもデータを返せるようにするフェイルセーフがあるが、最大クライアント数に達したときのエラーは
Redis::ConnectionError
ではなくRedis::CommandError
である。データベースから新鮮なデータが返らず、ユーザーに500エラーが表示された。
この修正は単にrescue
を変更してRedisのあらゆるエラーでリクエストをsaveする。もちろんエラーハンドラーにはエラーが報告されるので、エラーはユーザーが選択したメソッド経由で引き続き送信される。これは他のキャッシュストアと同様なので↓、実質的にすべてのエラーでsaveできる。
- MemCacheStoreはすべてのDalliエラーをrescueする(
Dalli::DalliError
)- ReadThis(別のRedisキャッシュ)は
Redis::BaseError
をrescueする- FileStoreは特定のrescueを宣言しないのですべてrescueする
同PRより
つっつきボイス:「Redisはコネクション数が最大になったときのエラーだけ種類が違ってたのか😳」「ReadThisっていうRedis互換のキャッシュストアがあるんですね」「dalliとどう違うのやら😆」「そういえばdalliってありましたね(ウォッチ20180413)」
- リポジトリ: sorentwo/readthis: Pooled active support compliant caching with redis
- リポジトリ: petergoldstein/dalli: High performance memcached client for Ruby
# sorentwo/readthisより
config.cache_store = :readthis_store, {
expires_in: 2.weeks.to_i,
namespace: 'cache',
redis: { url: ENV.fetch('REDIS_URL'), driver: :hiredis }
}
「ReadThisは見た感じ普通のキャッシュgemですね☺️」「もしかしてReadThisってRedisのダジャレか😆」「Redisみたいにライセンスであーだこーだ言わないよみたいな😆」「😆」「そういえばちょっと前から議論になってましたね」「Redisが使えなくなると他もいろいろ死にますし😭」
参考: Redis Labsの2度のライセンス変更はフリーライドを防げるか - ITmedia エンタープライズ
⚓(master、6.0.1)IE 9互換のためElement.closest()
を回避
# actionview/app/assets/javascripts/rails-ujs/utils/form.coffee#L12
inputs.forEach (input) ->
return if !input.name || input.disabled
- return if input.closest('fieldset[disabled]')
+ return if matches(input, 'fieldset[disabled] *')
if matches(input, 'select')
toArray(input.options).forEach (option) ->
params.push(name: input.name, value: option.value) if option.selected
else if input.checked or ['radio', 'checkbox', 'submit'].indexOf(input.type) == -1
params.push(name: input.name, value: input.value)
つっつきボイス:「そういえばElement.closest()
の互換問題ってありますね」「closest()
便利ですし😋」「一番近い要素を取れるんでしょうか?」「ツリーを上に遡っていって一番近いところにあるものを取ってくるヤツですね☺️」「なるほど!」「いくつ上に上がればいいかわからないときにホント便利😍」
参考: Element.closest()
- Web API | MDN
「この修正のファイル名見ると.coffeeってなってますけど、CoffeeScriptってまだ残ってるんですね😳」「入っているといえば入ってるみたいですね〜: 使われているかどうか知りませんが🤣」「🤣」
後で調べると、Action Viewのrails-ujs以下は現在もCoffeeScriptでした↓。
参考: rails/actionview/app/assets/javascripts/rails-ujs at master · rails/rails
なお#34177ではAction CableのCoffeeScriptがES2015に書き換えられました↓。
⚓(番外、master、6.0.1)Arel.sql
をstable APIとしてドキュメントに記載
Arel.sql
は他のAPIドキュメントやdeprecationメッセージから参照されているのに、それ自身にドキュメントがない。
同PRより大意
# activerecord/lib/arel.rb#L30
+ # 既知の安全なSQL文字列をラップしてクエリメソッドに渡せるようにする。例:
+ #
+ # Post.order(Arel.sql("length(title)")).last
+ #
+ # SQLインジェクションの脆弱性回避には万全の注意を払うこと。<a href="https://techracho.bpsinc.jp/wp-content/uploads/2019/07/ransack-h_captured.png"><img src="https://techracho.bpsinc.jp/wp-content/uploads/2019/07/ransack-h_captured.png" alt="" width="400" class="aligncenter size-full wp-image-78429" /></a>
+ # このメソッドでrequestパラメータやモデル属性といった「安全でない」値を使うべきではない。
+ #
def self.sql(raw_sql)
Arel::Nodes::SqlLiteral.new raw_sql
end
つっつきボイス:「Arel.sql
に今までAPIドキュメントがなかったので足したそうです」「Arel.sql
、こないだRansackあたりでちょっと使ったな〜😆」
その後社内Slackで、以下の記事↓とともに、回避手段としてのArel.sql
の存在感が再び増してきているのではないかという指摘がありました。ありがとうございます!🙇
参考: Rails 6 以降は order/pluck の引数に SQL 文字列を渡すことはできない (容易に対策可能) - Qiita
⚓Rails
⚓Pumaの新バージョンがリリース(Ruby Weeklyより)
- リポジトリ: puma/puma: A Ruby/Rack web server built for concurrency
- サイト: A Fast, Concurrent Web Server for Ruby & Rack - Puma
つっつきボイス:「Pumaの新しいのが出ましたね〜😋」「Pumaといえば以前公開つっつき会で見たあの動画ですね😆(ウォッチ20190708)」「ああ😆、バージョン3とさよならするあの動画↓」
By the coders who brought you Llamas in Pajamas. A new cinematic Ruby server experience. Directed by @evanphx, cinematography by @nateberkopec, produced by @schneems.
Introducing - Puma: 4 Fast 4 Furioushttps://t.co/06PG0lzubk pic.twitter.com/O1dLfwnctJ
— Richard Schneeman 🤠 (@schneems) June 25, 2019
「リリースノートには、URLでセミコロンが使えるようになったとかありました」
⚓0番ポートはany
Puma now reports the correct port when binding to port 0, also reports other listeners when binding to localhost (#1786)
「リリースノートにある0番ポートとのバインディング↑ってどういうものでしたっけ...?🤔」「0番ポートはless /etc/services
にはなかったけど、RFC1700に載ってるらしい↓」
参考: https://www.ietf.org/rfc/rfc1700.txt
Decimal Keyword Protocol References
------- ------- -------- ----------
0 Reserved [JBP]
1 ICMP Internet Control Message [RFC792,JBP]
2 IGMP Internet Group Management [RFC1112,JBP]
3 GGP Gateway-to-Gateway [RFC823,MB]
4 IP IP in IP (encasulation) [JBP]
5 ST Stream [RFC1190,IEN119,JWF]
6 TCP Transmission Control [RFC793,JBP]
7 UCL UCL [PK]
8 EGP Exterior Gateway Protocol [RFC888,DLM1]
9 IGP any private interior gateway [JBP]
(略)
「0番はreservedか」「well-knownポートか、思い出した: 任意のポートでソケットを開くときに0番ポートを使うんだった」「おぉ?」「自分でソケットを開くときに、空いているポートを使いたかったら0番ポートを指定すると開いてるephemeralポートから適当に割り当ててもらえる」「なるほど!」
参考: TCPやUDPにおけるポート番号の一覧 - Wikipedia
0番のポートはエニーポート(any port)と呼ばれ、アプリケーションに対して、動的に別番号の空きポートを割り当てるために用意された特殊なポート番号である。別番号のポートの再割り当てを行わずに0番のポートとして使用することは禁止されているため、利用上では注意が必要である。
Wikipediaより
「たしかephemeralポートの範囲はOSによって違ったはず」「そうなんですか!😳」
- IANA: 49152〜65535を提言
- BSD: バージョン5.0以降はIANAの提言に従う
- Linux: 32768〜61000が多い
- Windows: XPやServer 2003までは1025〜5000、VistaとServer 2008以降はIANAに従う
「手元のAmazon Linuxの/etc/servicesを見てみると↓、well-knownポートは0〜1023、registeredポートが1024〜49151、ダイナミックなプライベートポートは49152〜65535となってますね」「へぇ〜!」「IANAのサイトにも膨大なリストがあるな↓」「142ページもあるとは😳」「すごい量🐳」
参考: Service Name and Transport Protocol Port Number Registry
The latest IANA port assignments can be gotten from
http://www.iana.org/assignments/port-numbers
The Well Known Ports are those from 0 through 1023.
The Registered Ports are those from 1024 through 49151
The Dynamic and/or Private Ports are those from 49152 through 65535
Amazon Linuxの/etc/servicesより
「でPumaの話に戻ると、0番で任意ポートで立ち上げられるようになったということですね」「なるほど〜😋」「空いているポートを自分で調べて使うのってだるいですし😆」「たしかに😆」「空きポートを調べる処理って案外重たいんですよね: netstat
とかでやれますけど、仕組みがあるならそっちに任せてしまう方がいいかと」「そういえば最近はss
コマンドでやるらしいと昨日知りました😆」「最近のコマンドはわかんないな〜😆」「ss
ってなんか覚えにくいし😆」
参考: netstat - ホストのネットワーク統計や状態を確認する
参考: 【 ss 】コマンド――ネットワークのソケットの情報を出力する:Linux基本コマンドTips(150) - @IT
⚓スケールしたときのAPIエラーを正しく扱う(Ruby Weeklyより)
# 同記事より
def track_exception(exception)
redis.hincrby("tracked_exceptions", exception.class.to_s, 1)
raise Monolist::TrackedException.new(exception)
end
def poll_gitplace(user, client)
time = user.gitplace_last_sync
client.get_pull_requests({ created_after: time }).each do |pull_request|
comments = client.get_pull_request_comments(pull_request)
unless user.action_items.find { |s| s.github_id == pull_request.id }
create_action_item(user, pull_request, comments)
end
time = pull_request.created_at
end
rescue Gitplace::ConnectionTimeout => e
track_exception(e)
ensure
user.update!({ gitplace_last_sync: time })
end
見出し:
- リトライは早期に、ただし正しく
- 常にジョブの進捗を確認せよ
- 失敗をトラッキングせよ
つっつきボイス:「常にmake progressせよはそのとおり: 進捗取れてないとログ見ても何が起こってるかマジでわからないし😅」「なるほど!」「この記事は、APIをいっぱい叩くようなアプリを書くときはこの辺をちゃんとやっときましょうねという定番の注意ですね☺️」「ふむふむ」「最近自分もAPI周りでハマって面倒くさいことになってて😆」
「APIで何かするときに、やりとりが有限回で済むかどうかが事前にわからないときがあるんですよ」「あ〜😳」「データセットのサイズがめちゃくちゃでかいと、データをぶん投げるまでにものすごく時間がかかったりしますし😭」「たしかに!」「stagingでは一瞬で終わるのに本番だと永遠に返ってこなかったりして、そういうときにプログレス出してないとつらいです😇」
⚓RailsのDomain Objectsは善、Service Objectは悪(Ruby Weeklyより)
- 元記事: For organizing Rails projects, domain objects are good and service objects are bad - Code with Jason
見出し:
- Active Recordモデルの長所と短所
- 「Active Record寄せ集め」アンチパターンの代替に使われるService Object
- Service Objectがよくない理由
- Service ObjectよりもDomain Objectがよい
- もっと知りたい方へ
つっつきボイス:「久しぶりにオピニオン記事を見かけたので」「たしかにService ObjectよりはDomain Objectの方が設計としてはキレイになりますし、おっしゃるとおりという感じ😆」「😆」「Serivce Objectは自分にとって『設計を諦めて追いやる』的な位置づけというか😆」「😆」
「記事の見出しに『Active Record grab bagアンチパターン』というのがありますけど、grab bagはいわゆる『福袋』『寄せ集め』のことみたいなので、まあ闇鍋かなと😆」
「個人的にはService Objectってそれほどいいパターンには思えないんですけど、ただコードの見通しが悪くなったときに、昔なつかしいSOAP↓の内部API版みたいな感じで使うならワンチャンありかなという気はちょっとしますね🤔」「ふむふむ」「印象としてはそういうのがグローバルな名前空間にふらっと入ってくる感じ: もちろん使うならネームスペースちゃんと切りますけど😆」
「Service Objectにしたからといってキレイになったりはしませんし😆」「ただいろいろ条件を整えないといけないもので、かつ繰り返し実行するものならService Objectにしておいてさっと呼べるようにしておくはありかも🤔」「そうかも☺️」「Service Objectはそんなにうれしいパターンではないけど、価値がないわけではない💰」「コピペコードになりやすいのが難点かな😅」「Service Objectをキレイにキメるのは割と難しいです☺️」
「このDomain Objectは、この間のForm Object話(ウォッチ20190930)に出てきたApplication ObjectとかApplication Modelとかとはまた違うんでしょうか?」「Domain Objectは、たぶんここではビジネスオブジェクト的な、ビジネスロジックを置く場所という意味でしょうね☺️」「なるほど!」
「記事の下の方を見るとMartin Fowlerさんの薄いドメインモデル(Anemic Domain Model)↓のことが書かれてますね」「まさにエンタープライズアプリケーションアーキテクチャパターンで言われているような話かな☺️」
参考: AnemicDomainModel -- Martin Folwer
「なになに、『Devise gemはなかなかいい仕事をしてる』ですって🤣」「」「Devise嫌われてるけど🤣」「まあDeviseはでかいのと、どこを触ったら壊れるかがわからないのが怖いんですけどっ👻」
⚓Rails 6のZeitwerkを理解する(RubyFlowより)
見出し:
- Zeitberkの方がよい理由
- classicモードでのオートロード
- Zeitwerkのオートロード
- Rails 6のZeitwerk
つっつきボイス:「Zeitwerkの紹介というかおさらい的な」「内容はRailsガイドでも辿れそうな雰囲気でした」
参考: 定数の自動読み込みと再読み込み (Zeitwerk) - Rails ガイド
参考: 定数の自動読み込みと再読み込み (Classic) - Rails ガイド
「ところでZeitwerkはRubyのautoloadを使っているんですけど、autoloadはずうっと昔にRubyから消そうという話↓があったのをこの間教わって、今のRubyではどうなってるのかが気になりました🤔」「autoloadを消したいのは何となくわかるな〜: うまく動いているときはいいけど、ひとたび暴れ始めると大変そう😅」「下のissueの冒頭でも、autoloadはマルチスレッドで根本的な問題があるみたいなことが書かれてました」「そうでしょうね☺️」
「autoloadって結局消されないのかな?」「一度入れちゃったら無理でしょうね😆」「マルチスレッドのautoloadはカオスになるかもしれないけど、シングルスレッドだったらそういうことにはなりにくいんじゃないかな?🤔」「あとFiberとかなら😆」
「あ、今issueの一番下を見てみたらMatzが8か月前に取り下げてますね↓」「少なくともRuby 3.0では残すと」「8年越しの決定🎉」「autoloadは死なず」
⚓chef-sugar gemの作者が米国移民法に抗議のためリポジトリを閉鎖して議論に(Ruby Weeklyより)
- 元記事: Chef roasted for tech contract with family-separating US immigration, forks up attempt to quash protest • The Register
- リポジトリ: sethvargo/chef-sugar
https://twitter.com/shanley/status/1173692656192385024
つっつきボイス:「ああchef-sugarの問題ね☺️」「技術系じゃない英語記事ってあんまり読み慣れてなくて😅」「この件はちょっと前にもはてブで話題になってましたけど😆↓」「う、そうでしたか😅: じゃそっちで見ましょう」
参考: 政治的問題のためRuby GemsとGitHubからChef関連の諸々が消えた件について - tpdn blog
「これは元々、Chefの会社で働いてたメンテナーが、そこを辞めた後に元の会社がICEという政府機関と契約をしたのが気に入らなくて自分が関わったソフトウェアをリポジトリから消しちゃったという話😇」「すごいことするな〜😳」「1つだけかと思ったら他にも消してたとは😳」「あちこちでいっぱいアラートが鳴ってたでしょうね」「何だか壮絶😨」「ある日突然Railsがリポジトリから消えたらと考えたら...💀」
参考: アメリカ合衆国移民・関税執行局(ICE) - Wikipedia
「この件に関連して、オープンソースを反社会的なことに利用することについてのライセンス条項を見直すべきなのかどうかみたいな記事をはてブあたりで見た気がするんですが、今日ちょっと体力なくて見つけきれない😅」「そういう議論ってたしかに起きそうですね」「発端はさっきも話に出たRedisとかMongoDBなどのライセンス変更↓ですけど☺️」
参考: 「Redis」「MongoDB」「Kafka」が相次いで商用サービスを制限するライセンス変更 AWSなどによる「オープンソースのいいとこ取り」に反発 (1/3) - ITmedia エンタープライズ
後で探しましたが、やはりそれらしい記事は見つけられませんでした😇。
「Redisとかの件もそうですけど、それ以外にもたとえば人を害するプログラムを使ってはいけないという議論とかもあったりして、でもそれをどうやって実現するの?とか、とにかく最近のオープンソース界隈は議論が紛糾してますね☺️」「いろいろ考えさせられます😓」「う〜ん、やっぱり記事見つからないか😢」
「こういうのを見ると、gemをrubygems.orgとかから直接取ってくるんじゃなくて社内にリポジトリのミラーサーバーを立てて使うことで、サービス提供が中断しないように手を打つことも考えちゃいますね」「そういえばクックパッドさんとかもミラーやってますね」「そうそう、その方がより確実ですし☺️」「gemが汚染されたときにタイミングが悪いとミラーにしばらく残っちゃったりもしそう😅」「それもありますね」
⚓html5_validators: RailsでHTML5バリデーションを自動でやれる
この間amatsudaさんのリポジトリ↓(forkなどは除外)を物色してて知りました。
参考: amatsuda (Akira Matsuda) / Repositories
つっつきボイス:「リポジトリのタイトルにRails 3, Rails 4, Rails 5、Rails 6ってあるのがスゴい💪」「クライアントサイドバリデーション?」「ああなるほど!モデル側にバリデーションを付けるとビュー側でHTML5のこういうrequired
みたいなタグ↓を自動で使ってくれるのね😋」「おぉ〜😍」
# 同リポジトリより
class User
include ActiveModel::Validations
validates_presence_of :name
end
<input id="user_name" name="user[name]" required="required" type="text" />
「そういえばsimple_form↓もそういうタグを付けてくれた覚えが」「やってくれるみたいです」「simple_form、自分は割と好きなんだけど他の人がだいたいキライなので最近はあまり押さなくなってきてます😅」「simple_formはカスタマイズしないのがコツでしたっけ」「そうそう😆」
「html5_validators、割とよさそうですね😘」「まあ油断するとブラウザごとのバリデーション実装の違いにやられることもあるかもしれませんけど😆」「フォームで数字を指定したときのちっちゃ〜な上下矢印なんかはブラウザごとに違ってるし、しかもたいてい使いにくい😆」「ブラウザのカレンダーもたいがい使いにくいですし😆」「ブラウザ側の実装の違いはつらいよ〜😭」「ブラウザ組み込みのデフォルトのバリデーションメッセージも、たしか英語レベルですらブラウザごとに文言が違ってて泣いたことあります😭」
⚓その他Rails
- 元記事: Rails 6 adds add_foreign_key and remove_foreign_key for SQLite3 | BigBinary Blog(Ruby Weeklyより)
つっつきボイス:「SQLite3用だそうです」「SQLite3は使ってないな〜😆」「自分はSQLite3割と好きです❤️」「よほどじゃないと使いませんし、たまに使おうとするとSQLite3がそもそも入ってなかったりしますし😆」
@hachi8833 I’ll just answer here instead. The detail you mentioned was implied by the text, since `update_columns` is mentioned as a replacement for two calls to `update_attribute`, but I agree that it’s nice to make that more explicit. I’ve added a note to the tutorial. Thanks!
— Michael Hartl (@mhartl) October 2, 2019
つっつきボイス:「これは?」「以前のRailsウォッチ(ウォッチ20181210)で、Railsチュートリアルの演習問題にupdate_columns
(バリデーションやコールバックが発火しない)が使われているという話があったのをこの間やっと思い出して、作者のMichael HeartlさんにDMで知らせたところ一言注意を加えておくよという返信をもらったところです」「update_columns
の方が行数は少なくなりますけど、実際に使うとハマるやつですね☺️」
前編は以上です。
バックナンバー(2019年度第4四半期)
週刊Railsウォッチ(20191001後編)RedisとRubyをつなぐredis-object gem、Fullstaq Rubyの新バージョン、COUNT(*)とCOUNT(1)の速度ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSなど)です。