Tech Racho エンジニアの「?」を「!」に。
  • 開発

週刊Railsウォッチ(20170331)PostgreSQLの制約機能を使えるRein gemはビューも使えるほか

こんにちは、hachi8833です。

⭐ Rein: RDBMSの制約機能やビューを使えるgem(RubyWeeklyより) ⭐

RDBMSが持つ制約(constraint)機能などがRailsで利用しやすくなります。「PostgreSQLのみ」機能が多数あるので、事実上PostgreSQL専用に近そうです。

元記事はREADMEの抜粋のようなものなのでリポジトリを見るほうがよいでしょう。以下は同gemのREADMEにもとづいています。

Railsのマイグレーションファイルで以下のように記述できるようになります。

  • 外部キー(foreign key)制約
add_foreign_key_constraint :books, :authors     #作成
remove_foreign_key_constraint :books, :authors  #削除
  • inclusion制約(PostgreSQLのみ)
add_inclusion_constraint :books, :state, in: %w(available on_loan) #作成
remove_inclusion_constraint :books, :state                         #削除
  • 数値の制約(PostgreSQLのみ)
add_numericality_constraint :books, :publication_month,   #作成
  greater_than_or_equal_to: 1,
  less_than_or_equal_to: 12
remove_numericality_constraint :books, :publication_month #削除
  • Presence制約(PostgreSQLのみ)
add_presence_constraint :books, :isbn, if: "status = 'published'" #作成
remove_presence_constraint :books, :title                         #削除
  • 列挙(enumerated)型(PostgreSQLのみ)
create_enum_type :book_type, ['paperback', 'hardcover'] #作成
drop_enum_type :book_type                               #削除

データベースビューやスキーマも

一同でチェックしていると「こいつ...ビューも使えるぞ!」という喜びの声があがりました。

  • ビュー
create_view :available_books, "SELECT * FROM books WHERE state = 'available'" #作成
drop_view :available_books                                                    #削除

なおソースを覗いてみたところ、マテリアライズドビューではないようです。

  • 複数スキーマ(PostgreSQLのみ)
create_schema :archive  #作成
drop_schema :archive    #削除

果たしてどのぐらいイケているのかは試してみないとわかりませんが、こうしたgemなしでデータベース側の制約機能やビューをRailsで使おうとすると、生SQLとの格闘やマイグレーションでの整合性など何かと面倒になりがちだったので、うまくはまってくれれば助かりそうです。

既に似たようなコードを書いている方も多いと思いますので、車輪の再発明を減らす効果もあるかもしれません。

期待を込めて ⭐ を進呈いたします。おめでとうございます!

参考: PostgreSQL 9.0.4文書: 5.3. 制約

Ruby 2.2.7リリース(Ruby公式より)

Rubyの2.4.1とは別に、Rubyの2.2系のバグ修正として2.2.7がリリースされました。

ChangeLogがフラットすぎて読みづらいので、compareとってみました。やはりほとんどの修正が上位バージョンからのbackportですね。


https://github.com/ruby/ruby/より

Rails機能追加: belongs_to:defaultオプションを追加(Rails公式ニュースより)

belongs_toで以下のように書くと、自動的にbefore_validationコールバックが呼び出されるようになります。

belongs_to :person, default: -> { Current.person }

以下のようにいちいちチェックせずに済むのでちょっとだけ書きやすくなりますね。

belongs_to :person
before_validation -> { self.person ||= Current.person }

morimorihogeさんがチェックした修正箇所は以下のようになっているので、このdefault:||=含みですね。

# https://goo.gl/VeQJJ7 より
def default(record)
  writer(record) if reader.nil?
end

機能追加: RailsでRationalとComplexのduplicateをサポート(Rails公式ニュースより)

Rubyの次期バージョンでRationalとComplexのオブジェクトが複製可能になるとのことで、一足先にRails側で対応しています。

Complexes are not duplicable for RUBY_VERSION < 2.5.0:

ということなので、Ruby 2.5.0が出てからですね。

Rails側の修正のテストコードを整形してみました。

# https://goo.gl/nWJ7hg より
if RUBY_VERSION >= "2.5.0"
  RAISE_DUP = [method(:puts)]
  ALLOW_DUP = ["1",
               "symbol_from_string".to_sym,
               Object.new,
               /foo/,
               [],
               {},
               Time.now,
               Class.new,
               Module.new,
               BigDecimal.new("4.56"),
               nil,
               false,
               true,
               1,
               2.3,
               Complex(1),
               Rational(1)
               ]
   ...

RationalはTimeオブジェクトなどで内部的に使われていたりしますが、Complexってビジネスロジックにはまず出てこなさそうです。とはいうものの、理数系、特に電気工学では複素数が当たり前に使われるので、そうした方面での利用ではやはり助かると思います。

Rails修正: freezeしたオブジェクトでもTime#to_timeできるようになった(Rails公式ニュースより)

Rails 4以来の問題だったそうです。issueでは今回もpixeltrix氏から容赦ないツッコミが入っていますね。さらにpixeltrix氏自ら解決法まで示し、そして

knock yourself outは「どうぞご自由に」「やればー」みたいなニュアンスですね。

Rails修正: ActiveRecordの#orderにハッシュで正しく式を与えられるようになった(Rails公式ニュースより)

以下のようにハッシュのキーが式になっていると式がクエリにそのまま入ってしまう問題が修正されました。

Post.order("LENGTH(title)" => :asc).last
# SELECT  `posts`.* FROM `posts` ORDER BY `posts`.`LENGTH(title)` DESC LIMIT 1
#                                                  ↑残念

修正後のコードは以下です。項目がリテラルでない場合に展開していますね。

          # https://goo.gl/0juQNQ より
          when Hash
            arg.map { |field, dir|
              case field
              when Arel::Nodes::SqlLiteral
                field.send(dir.downcase)
              else
                arel_attribute(field).send(dir.downcase)
              end
            }

ハッシュのキーを式で動的に与えるのはあまりしないかもなー、という声もちらほらとありました。

新しいJSON APIにRailsを使うのをやめた理由(RubyWeeklyより)

Rails単体でまかなうアーキテクチャを変更し、RailsにマウントしたHanamiにAPI部分を任せる形になっています。初期のコードがいろいろひどくてリファクタリングが困難になったこともあり、新しいAPIをHanamiで試してみたようです。

That's why we decided to implement the new API as a standalone Hanami application mounted inside Rails. A change in the web UI (Rails) isn't reflected in the API (Hanami) and viceversa.

RailsとHanamiを共存させる手法は、この場合特に必然性があるかどうかはわかりませんが、他でも使えそうですね。

Hanamiをチラ見

ところで、HanamiはRailsよりも軽めで小ぶりなのかなという印象でしたが、必要そうなものはひととおりあるようですね。


https://github.com/hanami/hanamiより

ついでなので、それぞれのvendor/bundle/ruby/2.4.0/gems以下でfind . -type f -name '*.rb'| xargs cat| wc -lを実行してざっくり行数を取ってみました。

  • Rails 5.0.2: 391,259
  • Hanami 0.9.2: 161,059

Rails 5のWebSocketsアプリでActionCableのDoS攻撃脆弱性を見つけるまで(RubyWeeklyより)


ActionCable under stress: Finding a DoS vulnerability in Rails 5 WebSockets Appsより

非常に具体的で良い記事です。検証にはOS Xのネットワークツールも動員しています。

こちらは近日中に翻訳記事を公開いたしますのでご期待ください。

localtower: GUIでモデル、リレーション、マイグレーションを管理するgem(RubyWeeklyより)

このGUIで以下の操作を実行できます。

  • モデルの追加・削除・変更
  • カラム追加・削除・変更
  • 多対多リレーションの追加
  • マイグレーションの追加・変更・削除


https://github.com/damln/localtowerより

こういうのは個人的に好きなのですが、GUIだといろいろ痒いところに手が届かなさそうという声多数でした(´・ω・`)
ちょっと動かしてみたところ、作成したカラムは一律でインデックスがオンになりました。

スキーマ表示はきれいなので、顧客向けに整形するとかREADMEに貼るなどの使いみちはあるかもしれません。

教育用にも使えそうですが、生徒がGUIに味をしめてしまいそうなので考えどころですね。

少し似たツールとしては、以前のRailsウォッチでもご紹介したrails_db gemもありますね。

Ruby Heroes授与が終了(RubyWeeklyより)

2017年度のRubyConfでは行われないそうです。 Ruby HeroesはCode Schoolがスポンサーを務めていました。

別にお金などもらっていませんが、Code Schoolはいいですね。一部コンテンツが古いものがあるので頑張って欲しいです。

Rails 5.1のJS周りの詳細(RubyWeeklyより)

Rails 5.1でのYarn・Webpack関連情報がよくまとまっていて便利そうです。yarnでインストールする練習しておこう。

interferon: Ruby製のアラート用フレームワーク(RubyWeeklyより)

AirBnBで実際に使われているそうです。Ruby製ですが、特にRails用ということではなさそうでした。

なお、BPSのインフラチームはnagiosによるアラートをprometheusに移行すべく試験運用中です。push型のnagiousに対し、prometheusはpull型という特徴があります。

参考

Ruby 2D: クロスプラットフォーム2Dアプリ作成用 gem


http://www.ruby2d.com/learn/tech/より

アーキテクチャ図の左下にはしっかりSDLの文字も。Rubyでクロスプラットフォームなゲームをがっしがっし書きたい方向け。

# http://www.ruby2d.com/learn/get-started/ より
require 'ruby2d'

set title: "Hello Triangle"

Triangle.new(
  320,  50,
  540, 430,
  100, 430,
  ['red', 'green', 'blue']
)

show


www.ruby2d.comより

Uninterruptible: 軽いsocketサーバーを瞬時に再起動するgem

「Zero-downtime restarts for your trivial socket servers」とあるとおり、Un*x系のsocketプログラミングする人向けのgemですね。

READMEに挿入されている画像が、インフラエンジニアが日々仕事するときの心境を見事に表していていますね。ここに引用するのはさすがにやめておきます。

一同で記事をチェックしながら、morimorihogeさんがLinuxなどのUn*x系OSで使われているシグナルについておさらいしてくれました。

  • ターミナルのkillコマンドはプロセスにシグナルを送信するだけ: プロセス側が適切に応答しなければ意味がない
  • ただしSIGKILLkill -9)だけは例外: プロセスの実装に関係なくOSが強制的にプロセスを止める

参考: Ctrl+Cとkill -SIGINTの違いからLinuxプロセスグループを理解する

正規表現のよく使うパターン(HackerNewsより)

日付やURLやメアド、クレカ番号などにマッチする定番正規表現のメモです。私は動作確認してませんが、きっと便利です。HackerNewsでこれだけ人気が集まるということは、みんな正規表現で困ってるんですね。


mingrammer/commonregexより

Go言語用となってますが、Go標準のregexpライブラリは貧弱余分な機能がないのでたいていの正規表現でも動きそうです。

morimorihogeさんがピックアップしたIPv6用の正規表現↓に一同「これはひどいw」。

IPv6Pattern = \s*(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:[0-9A-Fa-f]{1,4}|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,3})|(?:(?::[0-9A-Fa-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,4})|(?:(?::[0-9A-Fa-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,5})|(?:(?::[0-9A-Fa-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9A-Fa-f]{1,4}:){1}(?:(?:(?::[0-9A-Fa-f]{1,4}){1,6})|(?:(?::[0-9A-Fa-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9A-Fa-f]{1,4}){1,7})|(?:(?::[0-9A-Fa-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*

そこから、IPv6は固定長ヘッダの採用によって低層デバイスでも容易に扱えるようになった一方、IPv6の省略表記一意に定まらないという絶妙に残念なルールのせいでパターンマッチング泣かせであることなどが話題にのぼりました。

  • ::の間がすべて0のフィールドが1つ以上連続している場合はその部分を::と省略してよい
    • ただしこの省略法は1つのアドレスで1回しか行ってはいけない
  • 上に該当しない場合、::の間に含まれる0は、0以外の桁がその部分にある限り省略してもよい

一応RFC5952でIPv6の推奨表記方法が述べられています。

参考: JPNIC IPv6アドレスの表記法とは

streisand: Ansible Playbook集(HackerNewsより)

HackerNewsで急上昇中のAnsible Playbookリストです。 ネイティブで対応できるサイトリストにはAmazon EC2、DigitalOcean、Google Compute Engine、Linode、Rackspaceがずらり。まだ増やすそうです。

Explainshell.com: コマンドのmanをシェル構文に沿ってビジュアル表示(HackerNewsより)


より

百聞は一見にしかずです。クールクール。

番外: iOS10.3のファイルパス問題について

これだけ日本語記事ですが、解説がとてもわかりやすくて助かりました。

Mac系OSには以前からファイル名のカタカナの濁点や半濁点が転送先で分離する問題がありますが、UTF-8への正規化(normalization)の残念なつくりが問題の根源だったとは。

# http://skyarts.com/blog/jp/skyarts/?p=31678 より
0xE30x830x94 <= ピ                //Normalization Form C (NFC) 
0xE30x830x92 0xE30x820x9A <= ヒ ゜ //Normalization Form D (NFD)

そしてAppleによる修正の見通しは暗そう...Macで保存した既存の大量のファイルはどうなるのでしょうか。

今週は以上です。

関連記事

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

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

Ruby 公式ニュース

Rails公式ニュース

Ruby Weekly

Hacker News

160928_1654_q6srdR


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。