週刊Railsウォッチ(20181210)update_columnは要注意、DBカラムコメントは書こう、個人情報扱いの注意点、Capistranoはやっぱりいいほか

こんにちは、hachi8833です。今年最後の公開つっつき会も盛況でした。ご参加いただいた皆さまありがとうございました!🙇

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを社内有志でつっついたときの会話です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

臨時ニュース: Ruby 2.6.0-rc1がリリース(Ruby公式ニュースより)

公開つっつき会の翌日のリリースでした。詳しくは上をご覧ください。

その後jnchitoさんの懇切丁寧なまとめ記事も出ました↓。

Rails: 先週の改修(Rails公式ニュースより)

Rails 5.2.2がリリース

今回社内のSlackで話題になったのは、GitHub上のreleases/tagの方がリリースノートがまとまっていて読みやすくなっていたという点でした。


つっつきボイス:「セキュリティ修正なのかな?」「今度のは普通のバグ修正のようです」「Rails 5.2.2リリースを少し詳しく見たいというリクエストをいただきましたので、他の項目は軽めで今回はここを中心に見ていく感じにしたいと思います😊」「単なるfix bugはさっと流していく感じで☺️」

エスケープ復元のバグ

Fix bug where URI.unescape would fail with mixed Unicode/escaped character input:

URI.unescapeのバグか↓」「の濁点が分離してるのかな?」「いや、これはエスケープの種類(8進数形式とURL形式)が複数混じっているときにコケるバグ」「あーそっちですね」「そもそも混ぜるな危険☠️」

URI.unescape("\xe3\x83\x90")  # => "バ"
URI.unescape("%E3%83%90")  # => "バ"
URI.unescape("\xe3\x83\x90%E3%83%90")  # => Encoding::CompatibilityError

Active Recordの#update*系メソッドは要注意

Allow aliased attributes to be used in #update_columns and #update.

#update_column#updateでエイリアスの属性を使えるようにしたと」

「ところでActive Recordの#update_columnといえば、良心的なRailsエンジニアなら普通は使わないメソッドで有名ですね😎」「ムフフ😎」「ムフフ😎」「基本、使うもんじゃない」「使ってないですー」

今日使いました😇」「おっと😆それは普通ならrejectされるか、さもなければNEEDFIXとか書かれるヤツです☺️」「自分も知らなかった💦」「今日でよかった☺️」

#update_columnメソッドがよろしくない理由ですが、昔のこの記事↓をちょっと開いてみてください(古い情報です)」

参考: » Railsのコールバックまとめ TECHSCORE BLOG

以下は同記事に記載されている時点のupdate_*系メソッドをざっくり分類したものです。

コールバックを実行する
update
update_attribute
update_attributes
update_attributes!
コールバックを実行しない
update_column
update_all
update_counters

「Active Recordでデータベースを更新するメソッドを大きく分けるとsaveupdateになるんですが、基本的にsaveを使うべき」「#updateはSQLのUPDATE文を発行するんですが、上のようにupdate系にはコールバック(フック)が動かないものがあります: この記事の時点の記述によれば、updateはコールバックを実行するのにupdate_columnはコールバックを実行しない」「マジで?😅」「一貫性が見えない…」「これがとてもわかりにくいので、#update_column#updateは基本使わない方がいい」

なお、Active Recordのコールバックでは以下のまとめ記事が有名ですが、その後#25503でupdate_attributeの挙動が修正されたりしているのでご注意ください。
参考: ActiveRecord の attribute 更新方法まとめ - Qiita

「コールバックが呼ばれないと何が起きるかという話もついでにしちゃいましょう: コールバックが呼ばれないと、before_*フックやafter_*フックと連動している処理が全部スキップされてしまいます」「😱」「そうすると、Railsのモデルの中で期待されている制約に違反するデータができてしまう可能性がある」

「そうした制約はRDBMSの側でCONSTRAINTとか使ってかけるべきという考え方“も”あるんですが、Railsではそうしたバリデーションなどは原則としてRubyのコードで行うという文化になっていますね」「あーそうなのか: 自分は両方でやるものかと思ってた」「そこはプロジェクトのポリシーにもよるので、絶対というものではありませんね☺️」

「実際そのあたりの棲み分けって悩ましくて、非常にシンプルなCONSTRAINTだったらRDBMS側でやってもいいんですけど、ビジネスロジックに属する制約をモデルから離れたRDBMSに置くのはちょっとねー、という思いもあるわけです」「おー」「RDBMS側に置いているビジネスロジックが複雑になってきたら、そのうちストアドプロシージャになってしまうんじゃないかと😆」「😆」

参考: ストアドプロシージャ - Wikipedia

「補足すると、ここで言っているRDBMSのCONSTRAINTというものは、NOT NULLなんかと同じような類の制約です: Railsから開発の道に入った人だとこの辺は普段あまり意識しないかもしれませんが」「まだNOT NULLしか使ったことなかった🤭」「RDBMSにはこうしたCONSTRAINTなどの機能が元々あるんですよ😚」

「それが実際のRailsアプリになると、だんだん単純な制約に収まらなくなってきて、たとえばカラムAがこういう状態のときはカラムBは何件以上なければならない、みたいな複雑な制約になるとCONSTRAINTだけでは表しきれないので、あくまでRDBMSでやろうとすると上述のストアドプロシージャを使うことになると」「ふーむ」「ストアドプロシージャの向こうにはが広がってますから🌘」「😆」

「ストアドプロシージャは、要するにRDBMSの中でプログラム(関数)を書いて実行できるようにする仕組み: ただし、いわゆる手続き型言語のプログラムとはちょっと趣が違う、特徴的な書き方をします」「PL/SQLはOracleのだったかな?」「そうですね」「とにかくストアドプロシージャはRDBMSごとに違う」「つまり互換性がない😇」

参考: PL/SQL - Wikipedia

「ストアドプロシージャで制約をかけていれば、仮にさっきの#update_columnメソッドを使ったとしてもRDBMS側でfailするので間違って更新されることはありませんけどね😆」「😆」

「まあそういうわけで、#update_columnは基本使わないこと: 使うなら#update_attributesにしましょう😍」

参考: ActiveRecord::Persistence

「実はattributeの呼び出しを1回にまとめようと思って#update_columnを使いました😅」「おっと〜、それは一番残念なパターン😆」「😆」「あ、そういえばその書き方、Railsチュートリアルに載ってますよ🤓」「ありゃ~😆」「それはアカンな〜😅」「後で探しときます: それは原作者にフィードバックしないと📩」

念のため、現時点の英語版↓で確認しました。

参考: Chapter 11: Account activation | Ruby on Rails Tutorial (Rails 5) | Softcover.io

追いかけボイス: 「このコードにはバリデーションがないので辛うじて直接の問題にはなっていませんが、チュートリアルとしては一言注意が必要ですね⚠️」

# 英語版Railsチュートリアル11章の演習より
class User < ApplicationRecord
  attr_accessor :remember_token, :activation_token
  before_save   :downcase_email
  before_create :create_activation_digest
  .
  .
  .
  # Activates an account.
  def activate
    update_columns(activated: FILL_IN, activated_at: FILL_IN)
  end

  # Sends activation email.
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

  private

    # Converts email to all lower-case.
    def downcase_email
      self.email = email.downcase
    end

    # Creates and assigns the activation token and digest.
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end

「後もうひとつ悩ましいのは、SQLにあるUPDATEやINSERTやDELETEと同じ名前のメソッドは利用を避ける方がいいのかなと思う一方で(#selectはまた意味が違うのでこの際置いとくとして)、そうとも言い切れないところがある点: というのも#update_attributesに相当するsaveのメソッドがないから」「むむ」「要するに、引数に属性を渡してそれを更新するメソッドがない」「savesaveですからね」「saveには属性を渡せないんですよねー😢: そこが覚えにくいところ…」「できそうでできないという😓」

先日のRails Developers Meetupで、#update_columnはその挙動を知ったうえであえて使うことはあるかもしれないという声もありました。いずれにしろカジュアルに使うものではなさそうですね。


「長くなりましたが、今回のActive Recordの修正は#update_column#updateでエイリアスの属性を使えるようにしたと」「使えなくていいんじゃないかしら🤣」

その他Active Recordの修正

※以下、changelogの引用ごとに話題が変わっています。ご了承ください🙇。

Fixes issue where “user post” is misinterpreted as “”user”.”post”” when quoting table names with the postgres adapter.

「次もActive Record」「あー、PostgreSQLのテーブル名にuser postみたいにスペースが入っていると""user"."post""と解釈されてしまう問題があったのか」「テーブル名にスペース…だと?😅」「普通に書いていれば踏みませんけどね☺️」


Cached columns_hash fields should be excluded from ResultSet#column_types

#34528も普通に開発する分には意識しなくてもよさそうかな」


Values of enum are frozen, raising an error when attempting to modify them.

「え、enumって今まで更新できた?😅: ああ、Active Recordでのenum(列挙型)サポートの問題を修正したのか」

「ところでenumって使ったことあります?」「うーん」「type系のカラムはenumを使う方が想定外の値が入らずに済むからいいという考え方もありますね☺️」

参考: 8.7. 列挙型 — PostgreSQL 10.5文書


update_columns now correctly raises ActiveModel::MissingAttributeError
if the attribute does not exist.

「これはさっきのupdate_columnsの修正とつながってそう」


Do not use prepared statement in queries that have a large number of binds.

「大量にbindするクエリではprepared statementを使わないと: そんなクエリはまず再利用しないだろうからキャッシュも効かないだろうし、それに重くなるだろうし: たぶんだけど」

「たとえばどういうクエリだとbindが大量になるんでしょうか?」「雑にやるなら、INにarrayを渡せば一発🌋: 軽く数MBのクエリができるし😆」「😆」

「他のfix系は書いてあるとおりだろうからだいたいいいかな」


Prevent leaking of user’s DB credentials on rails db:create failure.

「おー!」「db:createに失敗するとお漏らし🌊」

カラムコメントをちゃんと書いておくと後で身を助ける話

Fix bulk change table ignores comment option on PostgreSQL.

「これはマイグレーションの修正っぽい」「ところで皆さんはデータベースのテーブルやカラムにコメントって書いてます?」「あー」「あんまり…」「コメント、書いてもいいけどi18nとかで二重管理になったらヤダなー😅」「自分は、ちょろいテーブルならともかく、ゴツい仕様書が出てくるような案件では極力コメントを書いておきたいですね」

「今はマイグレーションでコメント書けばデフォルトでデータベースに入るんですよね」「ですです: 昔はmigration_commentsというgemを入れないとできなかった」

[Rails 5] マイグレーション時にデータベースのカラムにコメントを追加する

「データベースのカラムコメントをちゃんと書いておくと、後でDBツールからデータベース仕様書を自動生成できるという大きなメリット🎁があるんですよ、ね☺️」「ですね☺️」

「データベース仕様書をExcel形式で求められることってあるんですけど、Macだった頃はExcelの起動自体が重いし、仕様書を手書きするという無駄な仕事はぜひ避けたいので、コメントはデータベース側に入れておきたい」「Windowsに変わってからはどうですか?」「シートをダブルクリックするだけでExcelがすっと立ち上がるんで快適😂: クラッシュしないExcelってこんなにいいのかと😆」

Web開発環境をMacBook ProからWindows機に移行してみた話

「そうそう、吐き出した仕様をExcelに整形してくれるツールがあるんですが、何て名前だったかな🤔」「gemじゃなくて?」「gemじゃなーい: あの名前覚えられない」「あれ覚えられないっすよね😅」「あった: A5:SQL Mk-2↓: これは知っておくとマジでいいですよ❤️」

参考: A5:SQL Mk-2 - フリーの汎用SQL開発ツール/ER図ツール .. 松原正和

「これはほんとに神ツール⛩」「その用途としてはめちゃくちゃ使えるんですよね☺️」「いつぞやのウォッチにあったApache POIとはまた別?」「あれとは違いますね: こちらはデータベースをinspectしてテーブル定義書に整形してくれる」「これがないと生きていけない人いっぱいいそう😭」「これっこの論理名↓の列にコメントが入ってきてくれるっっ」「論理名って😆」「物理名が本来のカラム名ですか😆」「これならマイグレーション後の定義書更新もコワくない」


a5m2.mmatsubara.comより

「こういうテーブル定義書ってSI系のドキュメントの中では価値が高い方だと思いますね: 開発環境も手元になくてソースコードすらない状態でテーブル定義書しかもらえない、なんてこともあったりしますし😭」「それもなかったら相当キツイ😭」「テーブル定義書はないよりある方が全然ありがたい🙏」

「ただこういうドキュメントを人間が手書きするという行為がイヤなだけで😆、だからこそ、この最強ツールを活かすためにはコメントを日本語でみっちり入れておかないと、ね☺️」「カラムコメントを書いて怒られることはまずないし☺️」「特にプロジェクトが長期化して後からいろいろ機能が足されていくと、カラム名から機能が予測できないものがどうしても出てきてしまうんですよ、ね☺️」「ですね☺️辞書引かないとわからないようなカラム名とかがgemで入ってきたり」「そういうときにコメントで『これはXX gemで追加された』とか書いてあるだけで大助かり」


「で話をバグ修正に戻すと、お、このバグ踏んだことある気がする😓」「あれ?このコメントバグ修正した方、この間の公開つっつき会に来てた方なんじゃ…?😳」「えっマジで?まったく気づいてなかった😅」「Railsにもコミットしたりしてますって言ってましたね☺️」

Action Packの改修

「ところでAction Packって何をするところかわかります?」「う、わからない😅」「Action Packはやってることが多すぎるんですが😆、ルーティングとコントローラ周りを担当しています」「ヘルパーの一部もここにあった気がする」「自分の理解では、Action PackとAction Viewにあるヘルパーが合わさったものがビューで触れるヘルパーになるという感じ」「ですね: なんちゃら_urlみたいなのはルーティングのroutes.rbで解釈されてからでないとURLを引けないから、Action Packの方に入ってるはず」「あー、そっちに入ってるですか」「Action Viewのヘルパーはおそらく純粋に文字列を処理する方ですね」


Reset Capybara sessions if failed system test screenshot raising an exception.

「↑ちょうどCapybaraのバグ修正もここに出てる: ということはシステムテストのコンポーネントもAction Packに入ってるってことかな」「そうなの?😆」「(Action Packの中の)Action Dispatchの中に入ってますね」「Action Pack、何でも入ってる感」「Journeyなんてのもありますしね」「Railsの中で読むのが最も大変な部類」「Active Record並に読むの難しいですか?」「いい勝負かも😆」

Active Jobの改修

「Active Jobは最近になってだいぶ機能修正が進んできた感ありますね: もっと早く登場して欲しかったなと思いつつ」「いつからRailsに入ったんだっけ?」「4.2ですかね」「前回のウォッチで扱ったGlobalIDもActive Jobと一緒に入ったみたいです」「やっぱり割と最近なんだなー」

「ジョブ管理はたいていのアプリで使うものですが、Active Jobの登場が比較的遅かったこともあって、今でもActive Jobを使っていながらSidekiqを生で叩いてたりする人がいますし😆」「Active Jobが出たおかげで、もうrakeタスク書かなくていいんだー!ってすごく感動しました😂」

「そうそう、Active Jobをちゃんと使えば、今までrakeタスクでやってたことがジョブの形で書けるようになったのは大きな変化なのかなという気もしますし☺️」「Active Job登場以前は、普通ならジョブキューにぽいっと渡しておしまいにできるような軽量なジョブをコマンドラインで実行しようとすると、rakeタスク以外の選択肢がありませんでしたね😢」

「そしてrakeタスクはすっごく書きづらい!」「同意」「同意」「しかも起動が遅いし」「もともシェルスクリプトやmakeコマンドの代わりみたいなものですからね、rakeタスクって」「Railsのコンテキストで動かせるシェルスクリプト的な位置づけ」「rakeタスクはいろいろ融通が利かない」「Active Jobはちゃんと個別の小さなジョブを管理するという設計思想で作られているし、当然ながら非同期ワーカーに渡してやってもらうこともできるし」

「そういえばrailsコマンドでジョブを生成できた気がするけどどうやるんだっけか?」「generateはあるみたいだけど…」「あ、正確にはこんな感じのジョブのクラス↓をRailsランナーの引数で指定できるという機能でした」

参考: Active Job の基礎 | Rails ガイド

# Railsガイドより
# 明日正午に実行したいジョブをキューに登録する
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest) 

「今回の修正を見ていて、Active Jobはもっと積極的に使おうという気にだんだんなってきた😋」「😋」

Active Storageの改修

「Active Storageはまだまだ更新が続くだろうなと予測してます😋」「まだまだこれからですよねー?」「機能を単に使う分にはいいけど、カスタマイズしようとするとまだ何か踏むんじゃないかと😅」「今のところActive Storageを積極的に使おうという気にまだなってない🤓」


Fix uploading Tempfiles to Azure Storage.

「tmpファイルからAzureに直接置けるようになったと」「Azureだけバグってたのかな?😆」


「こうやって5.2.2の修正点をみんなでチェックするのっていいですね😋」「この間の5.2.1はそこそこクリティカルな修正でしたけど今回は割と普通の修正ですね」「こうやって細かく刻んでもらう方がうれしいという側面もありますね: 後で古いRailsアプリのコードを見たときに、これはあの頃に作られたんだなってわかったりしますし😆: マイナーバージョンが半年ぐらい続くと『これはいつのRailsだ?』ってなりそうだし」


「そういえば冒頭のGitHubのスクショにもありますが、GitHubのウォッチ機能にRelease Onlyが入ったのはさりげにデカイ: これでやっとリポジトリをウォッチする気になりましたもん😆」「今までのReleaseページはzipが置いてあるだけで情報がなかったんですが、今回の5.2.2はおそらくGitHubの改善に合わせてReleaseページにchangelogも掲載するようになったんじゃないかなって」「見やすいですー😂」

「ではそろそろ次へー👉」

ActiveRecord#cache_versionの生成にDBのtime文字列を使うようにしてパフォーマンスを向上

# activerecord/lib/active_record/integration.rb#L98
-   def cache_version
-     if cache_versioning && timestamp = try(:updated_at)
+       timestamp.utc.to_s(:usec)
+     return unless cache_versioning
+      if has_attribute?("updated_at")
+       timestamp = updated_at_before_type_cast
+       if can_use_fast_cache_version?(timestamp)
+         raw_timestamp_to_cache_version(timestamp)
+       elsif timestamp = updated_at
+         timestamp.utc.to_s(cache_timestamp_format)
+       end
+     else
+       if self.class.has_attribute?("updated_at")
+         raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
+       end
      end
    end

つっつきボイス:「英語タイトルだけ見ての予想ですが、今まではタイムゾーンを変えるとキャッシュが飛んじゃったのかな?それならこの修正はわかる」

「ちなみにアクセスがものすごく多いサイトでキャッシュを飛ばすと、最悪の場合アプリが落ちることもありますからね💀」「怖っ」「キャッシュがなくても動きそうなものなのに」「普通に落ちますよ😎: キャッシュが全部なくなってしまうと、サーバーにすべてのレンダリング処理が集中するし、レンダリングが終わらないうちに次々にリクエストがやってくるし」

「アクセスのほとんどないサイトなら、キャッシュを消してもその後でレンダリングされるから別にいいよね、という感じでやれるんですが、Yahoo!ニュースクラスのサイトでキャッシュなくなったら即死」「😱」「なのでそういう大規模サイトはキャッシュも厳密に管理してたりするし」

「で、コミットメッセージを読むと、:usec形式にすることでタイムゾーンに依存しないようにするようだ」「お、タイムゾーンをUTCにすると速くなるって」「おぉ~」「つまり、どちらかというとパフォーマンス改善がメインのPRということか」

「usecって単位知らなかった…😅」「普通に使いますヨ👓」「あ、msecがミリセカンドでnsecがナノセカンド、そのままだとマイクロセカンドもmsecになってしまって不便だからusecにしてるのかな」「ギリシャ文字のミューμがuに似てるからそれでuなのか」

参考: ミリ秒とは - IT用語辞典

ギリシャ文字が使えない環境などではμに形の似たアルファベット小文字の「u」(ユー)を用いて「us」「usec」と表記する場合もある。
同記事より

データベース書き込みをブロックする機能を追加

# 同PRより
ActiveRecord::Base.connected_to(role: :writing) do
  Dog.connection.while_blocking_writes do
    Dog.create! # 書き込みをブロックしているのでraiseされる
  end
end

ActiveRecord::Base.connected_to(role: :reading) do
  Dog.connection.while_blocking_writes do
    Dog.first # 書き込みではないのでraiseされない
  end
end

つっつきボイス:「一瞬考え込んじゃいましたが、このblockは動詞でした」「Rails 6のconnected_toの制御のようだ」「while_blocking_writesで囲むと、書き込みしたときだけraiseされるそうです」

「これはどんなときにうれしいんでしょう?」「うーん、あるとしたら、複雑なモデルをカスタマイズしているときなんかに、この部分では書き込みしないと宣言するときとかかなー🤔」「センシティブなデータを扱うときなんかに、誰かが勝手に書き込まないという安心感を得られるとか(この方がありそうかな)」

「プルリクを見ると、primaryとreplicaを使い分けるときなんかにいいかもってありますね」「あーなるほど、Rails 6のマルチデータベース対応の一環か: primaryとreplicaでデータを移行する処理を書いていると、両方に同じ名前のモデル名があることになって危ないけど、これで間違ってもprimaryに書き込まないようにできる☺️」「これは確かに欲しい!😂」「可読性も上がるし😋」

PostgreSQLの最小バージョンが9.3にアップした

# activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L426
      private
        def check_version
          if postgresql_version < 90100
            raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
          if postgresql_version < 90300
            raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.3."
          end
        end

つっつきボイス:「まあ新しいRailsでPostgreSQL 9.3を使うことはもうないだろうなー☺️」

番外: MySQLでutf8mb4文字セットのバリデーションとsupports_longer_index_key_prefix?を追加

これは例の6.0.0マイルストーンから見繕いました。

# activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L117
      def supports_longer_index_key_prefix?
        if mariadb?
          version >= "10.2.2"
        else
          version >= "5.7.9"
        end
      end

つっつきボイス:「おw、ちょうど今日これを踏んだ人いましたね〜😆」「いたいた😅」「おー、このプルリクを見るとやっぱりMySQLの5.7.9が境目だし😋」「MySQLはマイナーバージョンまでチェックしないとハマる」「MariaDBがいつの間にかバージョン10超えてるし☺️」「MariaDBはバージョニングまでMySQLと違うものになってるし」

「MariaDB追ってないな〜」「AWS AuroraのチームがMariaDBにかなりコミットしているらしいと聞いてますね」「へぇ〜😳」

関係ありませんが、アザラシとセイウチとオットセイの違いが未だによくわかりません。

参考: アザラシとアシカの違いは?オットセイやセイウチも。写真と文章で紹介 | morigasuki.net

「そういえばutf8mb4が出てきたので以下の寿司ビール記事↓も貼ってみました」「あ、longer index key prefixは寿司ビールとは別の問題ですね: これはこれで貼っておいていいと思います」「お、そうでしたか💦」

MySQLのencodingをutf8からutfmb4に変更して寿司ビール問題に対応する

「ともあれ、MySQLのinnodb large prefixは本当に超ハマる問題で、utf8mb4のカラムをインデックス化しようとしたときに起きる」「確か過去にその記事書いた気がする、と思ったら上の寿司ビール記事↑の中にあった↓」

Rails

Railsでデリケートな情報を扱うには(Ruby Weeklyより)


つっつきボイス:「どちらかというと運用視点かなと」「クレジットカード番号なんかは登録したくないのは当然として」「今どきTLS(SSL)なしでサイト立てるのもありえないし」「今ホットな情報銀行に保存するとか😆」「😆」(しばし情報銀行で盛り上がる)

参考: 情報銀行 - Wikipedia

「ちなみに個人情報を暗号化してデータベースに保存したことある人っています?」「ないかなー」「基幹システムでやったことあるかも」「暗号化した場合にできなくなることについて説明したのに、後になって検索したいとか言われたことならある🤣」「🤣」「無理無理🤣」「暗号化したらLIKEとか使えないし」

「他にはauditとか、Encryption as a Serviceとか」「ログにも注意、あるある: Railsのログをデバッグモードにするともうだだ漏れだし🤣」「後でログ見て腰抜かすヤツ🤣」

「このあたりをもっとガチガチにやりたいなら、たとえば個人情報のカラムはビューで直接レンダリングしないで、JSON経由で遅延レンダリングするぐらいの対策してもいいかも」「よくあるのが、キャッシュの設定をミスってCloudFrontのキャッシュにユーザーの個人情報ページが乗ってしまう事故⚠️」「🤣」「これは知っておかないと踏みそう😅」

「そういえばインドの旅館で、ルーターがキャッシュしてたせいで他人のマイページが見えてしまったという話ありましたね」「ひぇー🤣」「それはひどい🤣」「インターネットが高かった昔はそういうのが結構ありましたね: HTTTPプロトコルが主流だった頃」「マイページのURLがユーザーによって変わらない場合に、誰かがそのページを開いた後に別の人が自分の部屋で開くとそのページがキャッシュ経由で見えちゃうという現象ですね」「今はTLS(SSL)化されたことで経路レベルでは起きなくなりましたね」

「こうして見ると、かなり手広い記事: ごく常識的なことを網羅的に書いてあるし、センシティブな情報について意識したことない人がひととおりチェックするにはよさそう!」「無味乾燥なチェックリストよりはいいかも」「これ読みながらやればできそう」「一度は読んでおくべき」「もう少しカテゴリごとにグルーピングしてくれたらもっといいかな」「思いついた順に書いてるのかも?」「これ、翻訳したいです😍」

RailsのscaffoldとTDDは相性が悪い(Ruby Weeklyより)


つっつきボイス:「scaffoldでテストコードを生成するだけだったらマジ無意味😆」「確かに😆」

dpl: travis-ciのデプロイツール集(Awesome Rubyより)


つっつきボイス:「Travis-CIからデプロイするときのスクリプト集か」「割とズラッとありますね」


travis-ci.orgより

ここからCapistranoの話題になりました。

Capistranoは今も優れもの

「デプロイといえば今日ちょうど社内のチームミーティングで久しぶりにCapistranoの話をしたので簡単に」「すごくいい話でした😋」

「Capistranoって最近あまり話題にならないんですが、実はツールとして十分枯れていて完成度が高いなって改めて思ったわけです: Dockerでやろう勢からすればいろいろ言いたいことはあるかもしれませんが😆」「😆」

「sshしてgit pullして、シンボリックリンク張り替えてRailsリスタートして、みたいなデプロイだったらもうCapistranoで必要十分じゃないかって」「ロールバックも履歴管理もやってくれるし、Railsサーバーの再起動だけしたい、なんてニーズにも応えてくれるし、やっぱりよくできてる😍」

「で、最近Capistranoって名前をあまり見かけないなと」「検索すると2年前の記事とか出てきましたけど😆」「完成されてるから逆に話題にならなさそう?」

「でチームミーティングでは、最近加わった人がCapistranoの使い方がよくわからないという話をしてくれたので、ちょっと詳し目に解説しました」「Capistranoの詳しい話をあんなに聞けたのはマジ初めてでした」

「話しながら、実はCapistranoのいい使い方がよくわからなくて困ってる人が他にもいるんじゃないかって思ったわけですよ: ネットを見てても、Capistranoで十分じゃね?って思えるような内容をDocker-composeで必死にやってる記事をゴロゴロ見かけるし😆」「あーわかる😆」「本当にやりたかったのはsshしてデプロイしたいだけなのに、みたいな😆」「ついにはDockerに挫折して手動でsshしてgit pullしてたりとか😆」

「ともあれCapistranoをロストテクノロジー化するのはあまりにもったいないので、改めて盛り上がるといいなと」「同意」「特に最近Railsを始めた人だとCapistranoというこんな便利なツールがあることを知らないこともあるかもしれないし」「それありそう」「BPS社内ではCapistranoはもう空気のように当たり前に使われているので、改めて説明する機会が意外になかったなー」

「単にcap deployするだけだとCapistranoの具体的な動きを知らずじまいになってしまいがちだし🤔」「そういえばChefやAnsibleを説明するときに『これはCapistranoと似たような振る舞いでして』と話したら( ゚д゚)ポカーンとされたことあったし😆」「😆」「Chefでデプロイまでやるのはしんどくないですか?」「しんどいです😭なのでもうやめようかなと」「😆」「Chefはもともとプロビジョニングツールだし、デプロイとは概念が違いますしね🧐」「ChefはChef料理人がいないといろいろツライ」

参考: デプロイとプロビジョニングの違い - amichang’s blog

「で、さっきのTravisデプロイのリポジトリはというと」「puppetとかありますけど😆」「puppetを呼ぶんだろうか😆」「engine_yardとかもあるから、普通にシェルで叩くのと同じようなこともできそうかな」「取りあえずやれることは何でもここに置いてある感」「メンテされなくなったものがあったら消しといて欲しいな(ぽそ」「誰も消しに来ないんですよね😂」「😆」

参考: オープンソースの運用管理・運用自動化 / Puppetとは

Rubyで早速サーバーレスやってみた(Awesome Rubyより)


つっつきボイス:「いまが旬のヤツですね」「動かしてみた人います?」「まだー」「そうそう、このつっつきが終わったら、今日社内勉強会で発表したAWSアットアグランスのスライドをお見せしますよ😋」「😋」

参考: AWS Lambda RubyでNative Extensionsを使用するgemを使うには?serverlessも使ってみた! - GA technologies Tech Blog

その他Rails

Ruby

modulation: Rubyの依存関係を明示的に管理(Ruby Weeklyより)


つっつきボイス:「gemの管理?、モジュール同士の依存関係の管理?、どうやらモジュールをimport/exportするローダーっぽい🤔」「最近のJavaScriptみたいな」「もしかしてRubyのモジュールの扱いが気に入らない人が作ったのかも?😆」「あーなるほどね☺️」

参考: import文 — モジュール · JavaScriptの入門書 #jsprimer

「この書き方にそんな匂いをそこはかとなく感じる」「確かにESモジュールっぽい」「RubyだからDSL使えるでしょ!みたいな勢いに乗って書いてたりして😆」

# 同リポジトリより
export :User, :Session

class User
...
end

class Session
...
end
require 'modulation'
Models = import('./models')
...

user = Models::User.new(...)

...

「Ruby世界にはこういう分野もあるんだなって思いますね: 最近MatzがRubyのシンタックスハイライトは統一しなくていいみたいなことを言ってた気がするんですが、自分もいろんな書き方があっていいと思うし☺️」「☺️」「こういうgemが登場する余地があるぐらいだし、統一しなくてもいいんじゃないかなって😆」「あるいは無理だったり☺️」

Rubyで行う高度な例外ハンドリング

Ruby 2.1からException#causeというのが入っているそうです。


つっつきボイス:「どの辺がadvancedかなー?」「ああ、こういうネストした例外処理って、beginでraiseされ、rescueでまたraiseされてさらにrescueされてみたいな感じになりそう: nested rescueってマジ勘弁😭」「こーれーはーキツイ😅」

# 同記事より
class A < StandardError; end
class B < StandardError; end

the_exception = nil
begin
  begin
    raise A
  rescue
    raise B
  end
rescue => exc
  the_exception = exc
end

the_exception # #<B: B>
the_exception.cause # #<A: A>
the_exception.cause.cause # nil

「個人的にはですが、Rubyでrescueだけかけるのがあまり好きでない: どれを捕捉するのかわからなくなりそうでコワい😰」「Rubyのチェリー本↓にもむやみにrescue使うなって書いてあった気がします」

「ところがRailsの公式な手順だかチュートリアルだかで、コントローラの中で最後にrescueして、ダメだったときにそれで拾うみたいな書き方が確かあって、しかもRubyMineだとそこでインデントが崩れるという😆」「😆」

「記事の人は『causeスゴイから!』って感じで書いてますね☺️」「ところでこのreraise_withって😆」「リレイズ😆」「ファイナルファンタジー臭しかしない😆」「センス光る😆」「😆」「いやーダメでしょーそれやっちゃ😆」「reraise_withの中でまたreraise_withしてる時点で、これは使っちゃダメだってオレの心がそう言ってる😆」

「まあ内側でraiseしたのを外でもう1回raiseするときにエラーオブジェクトを握りつぶさずにすべてをスタックトレースで辿れるようにしたってことなのかなとは思うんですが、もっといいベストプラクティスがあるんじゃないかしらと☺️」

追いかけボイス

参考: ネストした例外の場合、causeも自動的に出力されるようになった — サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita

Fiberってなぜあるの?(Ruby Weeklyより)


つっつきボイス:「GuildじゃなくてFiber?」「例のRubyのライブラリです」「Fiberは大量のアクセスをさばかないといけないマルチスレッドアプリを書くのにはよさそうな設計だなと思いますね」「永遠に起こされないFiberとか作られそうだけど😆」

参考: class Fiber (Ruby 2.5.0)

2019 Fukuoka Ruby Awardの募集開始(Ruby公式ニュースより)

賞金100万円ですよ。

ちなみにRuby bizグランプリの応募受付は終了しました。


つっつきボイス:「この間のRuby忘年会で高橋会長が呼びかけてたので」「Ruby bizの方はBPSも応募したのでエントリに載ってますヨ(受賞はしませんでしたが)」「知らなかった!😳」

その他Ruby

Ruby trunkより

もっとRefinementしたい

# 同issueより
# Access key value with method
using Module.new {
    refine Hash do
        # name is Symbol or String
        def method_missing(name)
            self[name.to_sym] || self[name.to_s]
        end
    end
}

hash = { name: "homu", "age" => 14 }
pp hash.name
# => "homu"
pp hash.age
# => "age"

つっつきボイス:「どちらも同じ方からのissueです」「refinement、消したい人もいるかと思うとこういうのも☺️」「そういえばはてブでrefinement対決みたいな記事が上がってた気がする」「refinementしないといけないようなコードは使いたくないな〜😅」

「よく見たら、これ#method_missingでやりたいって…」「な…んだと…?😆」「つまり今はできないのか!」「禁断の魔法っぽい」「どんないいことがあるんだろっ?」「これはもうrefinement強者にお任せしたい」

そういえばRuby 2.6ではpublic_sendなどで呼ばれてもrefinementが効くようになったんですね。

参考: サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita

クラウド/コンテナ/インフラ/Linux/Serverless

clair: コンテナの脆弱性を静的チェック


同リポジトリより

CoreOS社のロゴのデザインがちょっと好きです。


coreos.comより

SQL

DB WeeklyはAWS reInvent一色な感じでした。

SQLインジェクションのテクニック4種(DB Weeklyより)


つっつきボイス:「ここにいる皆さんはだいたいご存知なんだろうなと思いつつ」「SQLインジェクションは知っておく方がいいですよね: 自分が使うことはないにしてもw、アプリで脆弱性が発覚したときに影響範囲を推測するためにも知っておくのが大事🧐」「今すぐサイトをたたまないと危ないのか、このログを見て問題なければ大丈夫なのか、とかを見極められないと」

Neo4j: グラフデータベース(DB Weeklyより)


つっつきボイス:「Neo4j、どこかで聞いたことある」「グラフデータベースって、グラフ理論のグラフでしょうか?」「ですね」「やっぱり」「グラフデータベースはいろいろありますね」

参考: グラフデータベースとは? | アマゾン ウェブ サービス (AWS)

その他SQL


つっつきボイス:「psqlでCSVを吐き出せるという短い記事です」「お、CSVを書き出すだけなら前からありますが、psqlのオプションで書き出せるなら、それなりに意義がありますね: 権限がなくても書き出せるから」「あー」

「PostgreSQLには元々SELECTしたものをファイルに書き出せるOUTFILEというものがあるんですけど、これを使ってCSVを書き出すにはそのPostgreSQLユーザーにOUTFILEの権限がGRANTされてないといけないし、かつそのPostgreSQLユーザーが出力先のファイルシステムに書き込み権限を持っていないと、できない」「そっかー!」

「この障壁が意外に高くて、ちゃんとセキュアに設定されたPostgreSQLではOUTFILE権限を与えていないのが普通なんですね: 特にSE Linuxがtargetedモードで動いていたりするとPostgreSQLのプロセスから/tmpにアクセスできなかったりしますし」「なるほどー!!」「まあ1度標準出力に出してからゴニョゴニョすればやりようはあるんですが: この記事のはpsqlコマンドのオプションということだからそれを回避できるということだと思います」「こういうことでハマった経験がないとわからない微妙な嬉しさ😆」「😆」「こうやって話を聞くとありがたみがわかってくる」

追記(2018/12/11): 以下をmorimorihogeさんに補足いただきました🙇。

PostgreSQLでpsqlするときには、以下の3つのユーザーが関連します:

  • A: psqlコマンドを実行したUNIXユーザー(プロセスに紐付いているOSのユーザー)
  • B: psqlの-Uオプション等で指定されるPostgreSQLで管理されているPostgreSQLユーザー(PostgreSQL管理内のDBユーザー)
  • C: PostgreSQLプロセスを実行するUNIXユーザー(プロセスに紐付いているOSのユーザー)

OUTFILE記述の場合、BではGRANTとして明示的にOUTFILE権限が必要な上に、Cで出力先にファイルを書き込む権限が必要。

そして、PostgreSQLプロセスがSE Linuxのtargetedモードやapparmor経由で動いている場合、ユーザーディレクトリはそもそも書き込もうと思ってもファイルを書き込めなかったりする設定になっていることが多いです。

今回のcsv output機能では、BのOUTFILE権限はいらず(SELECT権限は必要)、Aのファイル書き込み権限さえあればいけるので、よくある「お客さんからXXXの集計データが欲しい」と言われたときに、ログインしたメンテユーザーの~/workディレクトリに簡単に出力できるようになった、という話になります。
ただ、元々OUTFILEしなくても出力結果を標準出力に出すことはやろうと思えばできました。

※以下のpsqlコマンド版の話。COPY TO形式の方はPostgreSQLユーザーでファイル書き込みするのでBCの権限両方必要なはず。

参考: postgresでcsv出力 \- Qiita

↑の記事のCOPY TOの補足に「DBサーバーから見たパス」という記述もありますが、確かにPostgreSQLプロセスが間違って越境しないようにPG_DATAディレクトリにchrootして動いてたりすると、さらに混乱はありそうではある。

JavaScript

stateofjs.com: JavaScriptの最近の傾向のまとめサイト


同サイトより

周期表っぽいデザインです。

参考: 周期表 - Wikipedia


つっつきボイス:「サイトデザインやたら凝ってます」「もうみんなES6でいいでしょっ😆」「JavaScript開発者の給与分布まで載ってるし」「ごく…」「こういうアンケートに答える人はだいたい強者ばっかりですけどね😆」「😆」「😆」「サイトを作る側にしてみれば給与分布を上げ底するインセンティブありまくりだし😆」「あーたしかに」「正直に書くメリットがないという😆」「答える人も高めに答えるだろうし」「そこのところを差し引かないとですね🧐」

CSS/HTML/フロントエンド/テスト

最近のCSS Reset事情


つっつきボイス:「CSS Reset、久しぶりに見た」「今日これの翻訳記事を見た気がします」「おぉー」

ありました↓。

参考: CSSリセットの現状、どのCSSリセットが適しているか選ぶ際の指針 | コリス

「そういえば、特にBootstrapで使われているCSSリセットファイルのコメントでは、どうしてそういうリセットにしたのかという理由が書かれていて、読んでいてへぇ〜っと思いますね: たとえばIEのこのバージョンではこういう問題が発生するからとか、こんなブラウザバグがあるとか」「お〜」「勉強になりそう!」

後で調べると、Bootstrap 4ではReboot.cssというものが使われていました。

参考: Reboot · Bootstrap
参考: Reboot.css Bootstrap製Reset.cssからCSSの新しいスタンダードを読み解く | Goodpatch Blog

言語

最近のMicrosoftの動向

あとこんなのも↓。

追記: その後本当になりました。

PHPむずい


つっつきボイス:「これはもうペチパー必須科目😆」「😆」「覚えられる気がしない…」

その他

GitHub Leaning Labとは


lab.github.comより


つっつきボイス:「詳しく見る暇なしのまま貼ってみました」「GitHubを使うためのチュートリアルか」「これはいい試みだと思いますね👍」

あとこんなのも↓。

番外

さいなら~


つっつきボイス:「ポケベル終わりましたねー☺️」「停波だから完全終了」「ポケベル世代?」「のはずですが使ってない😆」「世代じゃないけど使ってない😆」「親父が記者だったので背広のポケットで見つけたことあるだけでした: ベル鳴らす機能しかない最初期のヤツ」

「📟」というポケベルの絵文字があることに今頃気づきました。


今回は以上です。

「お疲れさまでしたー」「ちょっと早いけどよいお年を〜」「よいお年を〜」

その後の懇親会🍕🍺では、AWS reInventアットアグランスのスライドで盛り上がりました。参加いただいた皆さま、ありがとうございます!

お便り発掘

週刊Railsウォッチ(20181210)update_columnは要注意、DBカラムコメントは書こう、個人情報扱いの注意点、Capistranoはやっぱりいいほか

Capistrano、もっといい方法がさすがにできているのかなあと思いながら使い続けているんだけど、いいんだ! よかった!

2018/12/11 12:37

バックナンバー(2018年度後半)

週刊Railsウォッチ(20181203)Railsのglobalidとは、AWS LambdaがRubyに対応、JSはPromiseを最初に学べほか

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。

Ruby 公式ニュース

Rails公式ニュース

Ruby Weekly

Awesome Ruby

RubyFlow

160928_1638_XvIP4h

Publickey

publickey_banner_captured

Postgres Weekly

postgres_weekly_banner

DB Weekly

db_weekly_banner

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ

BPSアドベントカレンダー