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

週刊Railsウォッチ(20190513-1/2前編)6.0の地味に嬉しい機能、ActiveModelエラーの扱いが変更、Railsのリクエスト/レスポンスをビジュアル表示ほか

こんにちは、hachi8833です。

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

5/9の令和初の公開つっつきはおかげさまで盛況となりました。お集まりいただいた皆さまありがとうございます!🙇

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

今回はGW前の公式ニュースから見繕いました。最近のコミットリストを見るとドキュメントの更新が増えていて、リリースが遠くないことを感じさせます。

モデルのエラーをオブジェクト化、APIを変更

単一のエラーをカプセル化するActiveModel::Errorを追加。メッセージ生成や詳細へのアクセスを扱う。これをErrorsクラスで使い、ハッシュベースのインターフェイスからErrorオブジェクトの配列に変更する。whereなどのより柔軟なクエリメソッド群を追加。
PRより大意

# activemodel/lib/active_model/error.rb#L3
module ActiveModel
+ # == Active \Model \Error
+ #
+ # Represents one single error
+ class Error
+   CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
+   MESSAGE_OPTIONS = [:message]
+
+   def initialize(base, attribute, type = :invalid, **options)
+     @base = base
+     @attribute = attribute
+     @raw_type = type
+     @type = type || :invalid
+     @options = options
+   end
...
+   attr_reader :base, :attribute, :type, :raw_type, :options
+
+   def message
+     case raw_type
+     when Symbol
+       base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS))
+     else
+       raw_type
+     end
+   end
...
+   protected
+
+     def attributes_for_hash
+       [@base, @attribute, @raw_type, @options]
+     end
+ end
+end

つっつきボイス:「おー、ActiveModel::Errorクラスを作ったと」「変更追加の行数がかなり多いからがっつり再実装してるっぽい」「Active Modelのエラーをwhereとかで絞り込めるようになったように見える」「ほんとだ、プルリクの解説にも書いてありますね↓」「これは確かにありがたい!🙏」

model.errors.where(:name, :foo, bar: 3).first

「今まではできなかったんですね」「従来のハッシュだと気合いでeachするしかなかったし😆: 今までのだと、Active Modelにバリデーションエラーを追加するときにキーがかぶると困ったんですよ😭」「arrayに変わったことで、そのあたりをあまり気にせずにやれるようになった😋」

「これかなりよさそうなのでPRの👍押しとこうっと: でも既存のgemへの影響とかそこそこありそうな気も🤔」「言われてみればテストにもassert_deprecatedがいっぱい付いてますね」「割と大きな変更だと思う」

「Active Modelをどの程度までオブジェクト指向に作るかという設計の話の気もしますね: ハッシュの方が何も考えずに使えるという考え方もあるだろうし、オブジェクト指向的にきれいにやろうとするなら今回みたいにする方があるべき姿だろうし」「ふーむ」「自分は今回の変更の方が好き❤️」

API変更を抜粋しました。

[]
変更なし、非推奨化(今後はmessages_for
as_json, blank?, clear, count, empty?, add
変更なし
added?
ほぼ変更なし(1箇所変更: "Testing is more precise and flexible"を参照)
delete
拡張された(エラーの種類やオプションなどの詳しい条件を指定できるようになった)
each
each{|attr,msgs|}は従来どおり(非推奨化)
each{|error|}Errorの配列をループで回す
full_message
非推奨化(不要になった)
変更されなかったメッセージはErrorで生成される
full_messages, full_messages_for, include?, size, to_hash, to_xml, to_a, messages, details
変更なし
messages_for
追加(非推奨の[]を置き換える)
where
追加(エラーオブジェクトへのクエリ)
generate_message, has_key?, key?, keys, values
非推奨化
import
追加(ネステッドエラーとしてエラーを1つインポート)(Form Objectやnested attributesでのエラーのインポートに便利)

zeitwerk:checkタスクを実装

アプリケーションをRails 6にアップグレードするときに、従来のオートローダーを用いているプロジェクト構造が:zeitwerkモードと互換性があるかどうかを以下のコマンドでチェックできる。
PRより大意

bin/rails zeitwerk:check

つっつきボイス:「以前のオートローダーとzeitwerkモードで互換性があるかどうかをチェックするんだそうです」「そんなの動かしてみないとわからなそうだけど😆: 従来のオートローダーは実行時解決だから」「あー」「コード読まないとわかんないけど、空のRailsランナーを動かして通るかどうかをチェックしてるとかそういうノリ?」「コンパチブルチェックと言いつつ、zeitwerkに変えて動くかどうかぐらいのレベルのように思えるけど😆」「ここはひとつRails 6を触っている人たちにぜひチャレンジしていただきたい😆」

Active Jobの古いジョブのリトライ

# activejob/lib/active_job/exceptions.rb#L50
      def retry_on(*exceptions, wait: 3.seconds, attempts: 5, queue: nil, priority: nil)
        rescue_from(*exceptions) do |error|
-         # Guard against jobs that were persisted before we started having individual executions counters per retry_on
-         self.exception_executions ||= {}
-         self.exception_executions[exceptions.to_s] = (exception_executions[exceptions.to_s] || 0) + 1
+         executions = executions_for(exceptions)

-         if exception_executions[exceptions.to_s] < attempts
-           retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: exception_executions[exceptions.to_s]), queue: queue, priority: priority, error: error
+         if executions < attempts
+           retry_job wait: determine_delay(seconds_or_duration_or_algorithm: wait, executions: executions), queue: queue, priority: priority, error: error
          else
            if block_given?
              instrument :retry_stopped, error: error do
                yield self, error
              end
            else
              instrument :retry_stopped, error: error
              raise error
            end
          end
        end

つっつきボイス:「ジョブのリトライか〜😅」「プルリクメッセージを見ると、Rails 6にアップグレードしたときに、Rails 5.2のときの古いジョブをリトライできるようにしたとある」「ジョブのフォーマットが5.2と6で変わっていたということなのかな」

「たしかにこれやっておかないといけないヤツ: Rails 6から始まったプロジェクトならいいけど、Rails 5.2でジョブキューがたまっている状態で6にアップグレードするとジョブキューが動かなくなってたという話なんでしょうね」「これ現場で起きたらめちゃめちゃ悲惨ですよね😅」「これ踏んだらヤバい😇: リトライできないジョブをどうやって復旧させるかを考えるだけで🤣」「Sidekiqの生のジョブキューとにらめっこして復元方法を考えるとかやりたくない〜😭」「果たしてロールバックできるんしょうか😭」

Active Record高速化2連発

# activerecord/lib/active_record/attribute_methods/before_type_cast.rb#L48
      def read_attribute_before_type_cast(attr_name)
-       sync_with_transaction_state
+       sync_with_transaction_state if @transaction_state&.finalized?
        @attributes[attr_name.to_s].value_before_type_cast
      end
# activerecord/lib/active_record/attribute_methods.rb#L467
      def pk_attribute?(name)
-       name == self.class.primary_key
+       name == @primary_key
      end

つっつきボイス:「またしても@kamipoさんの高速化です」「やっぱり@kamipoさんはすごい人💪」「こういう地道な改修がホント大事🙏」「Active Recordのコード生成系の処理にこういうのが残ってたのか」「Active Recordのソースコードをここまで読み込んでる人って他にいなさそう」「@kamipoさんはこういうのをどうやって見つけるんでしょう?」「わがんね🤣: frozenでないものとかを地道に見つけて修正してるのかも」

「以下の差分の-って何でしたっけ?」「これはfreezeしたstringを返すヤツですね」「そうでした😅」「3回ぐらい見かけたのでさすがに覚えた😆」

# activerecord/lib/active_record/attribute_methods/primary_key.rb#L43
          def primary_key=(value)
-           @primary_key        = value && value.to_s
+           @primary_key        = value && -value.to_s
            @quoted_primary_key = nil
            @attributes_builder = nil
          end

参考: instance method String#-@ (Ruby 2.6.0)

番外: 孤立化したレコードを検索するmissingメソッド

# activerecord/lib/active_record/relation/query_methods.rb#L
+     def missing(*args)
+       args.each do |arg|
+         reflection = @scope.klass._reflect_on_association(arg)
+         opts = { reflection.table_name => { reflection.association_primary_key => nil } }
+         @scope.left_outer_joins!(arg)
+         @scope.where!(opts)
+       end
+
+       @scope
+     end

つっつきボイス:「まだマージされていませんが、Gobyの@st0012さんが『これよさそう』って教えてくれたPRです」「missingはあれば使うかも😋: has_many関係で、manyされている側で参照元がなくなっているものを探せるヤツですね」「お〜」「この間ぐぐってみたところ、このorphan recordはデータベース用語として一般的に使われているもののようです🧐」「たまにデータベースの掃除をしたいときなんかにmissingが便利そう🥰」

Post.where.missing(:author)

{他動} : 〜を孤児にする、親を失わせる、独りぼっちにさせる
{名・形-1} : 孤児(の)、親のない(人)、親をなくした(人)
{名・形-2} : オーファン(の)、孤立行(の)◆ページの末尾に残された、段落の最初の1行。2行目以降は次のページに送られている。

参考: What is an Orphaned Record? | Database.Guide

その他改修

つっつきボイス:「HashWithIndifferentAccessってHWIAと略されることありますよね: 最初見たときわかんなかった😆」「HABTMなんて略語もありましたね」「はぶたむはもういいや😆: Railsにはもう存在しないし」

参考: ActiveSupport::HashWithIndifferentAccess
参考: HABTMリレーションシップは悪であるという論争 | A-Listers


つっつきボイス:「はー、where.notの動作がRails 6.1でNORからNANDに変わると」「あんまり使ってる人いなかったのかな?」「where.notって個人的には、気持ち悪いとまではいかなくても、ドットも含めてワンセットになっているのが何となく使いづらい気がするんですけど😅」「使うは使うけど、他にもメソッドがチェインされているとto_sqlしてどんなSQLが出てくるのか調べないと落ち着かない😆」「not_whereみたいな名前ならよかったかも☺️」

つっつきボイス:「ActiveModel::Attributesattribute_namesってなかったんだ!」「ハッシュのkeysに相当するものを付けた感じ」


つっつきボイス:「join_type...だと?」「あ、InnerJoinOuterJoinを指定できるようになったのか」「これはあっていい気がする、というかこの方がどういうSQLができるか見当がつきやすいし😆」「自分はORM登場前からSQL使ってたのもあって、メソッドチェインが深くなるとto_sqlしてSQLを確認しないと不安になるところがあるんですが、こういうやり方なら多少気持ちの安寧を得られるかなと😆」「このあたりORMネイティブ世代だとどう思うか知りたいところではありますね☺️」

Rails

Rails 6の地味に嬉しい機能たち(Ruby Weeklyより)


つっつきボイス:「これ系の記事は定期的に出てきますね☺️」「TechRachoの翻訳記事でお世話になってるEvil Martiansさんの記事です」「お、Evil Martiansの人たちはRubyKaigi 2019にも来てましたね、つーか発表してた↓」

「記事の方ですが、Railsウォッチを読んでいる方にはだいたいお馴染みのものが多そうでした」「Action MailboxにAction Textにマルチデータベースにパラレルテストあたりはだいたい言い尽くされている感ありますね」

「おー、Active Storageのダイレクトアップロード機能: ちょうど以下の図↓みたいに、Railsサーバーを経由せずにS3みたいなクラウドストレージにアップロードする機能ということだと思います」「お〜」「普通に実装するとまずRailsサーバーにアップロードしてからS3にアップロードするみたいになるんですが、ダイレクトアップロードではS3の使い捨てトークンを使って直接S3に投げられる🧐」

参考: Active Storage meets GraphQL: Direct Uploads - DEV Community 👩‍💻👨‍💻


dev.to/evilmartiansより

「ダイレクトアップロードみたいな方式がありがたいのは、ファイルのアップロードのためだけにRailsのワーカーを保持しないで済むところ😋」「ある程度の規模のアプリになったらこういうのを真面目に実装しておかないと、管理者が管理画面で巨大ファイルをアップロードするとユーザーのフロント側が詰まるなんてことが起きかねないので😇」「あ〜なるほど」「こういうのを自前で実装するのは大変なので、Railsの機能にお任せでやれるのはありがたい🙏」

参考: ダイレクトアップロード -- Active Storage の概要 - Rails ガイド

insert_allとかupsert_allあたりはウォッチでやったかな」「dirty周りでは、PostgreSQLのJSONBでもchanged?的なことができるようになってるらしい」「optimizer hintsもあったな〜」

destroy_byとかtouch_allあたりは使いそうだけどそのときに忘れてそうな気も🤣」「人が使ってるのを見て思い出したりして😆」

最近のService Object

社内SlackでService Objectの話題が出たので。Service Objectには「Facadeパターン」か「Commandパターン」の2つの方法があるという流れでした。

Railsで重要なパターンpart 1: Service Object(翻訳)


つっつきボイス:「そうそう、最近Service ObjectがBPS社内でも話題になってたタイミングでwillnetさんがとてもいい記事を書いてくれてた❤️」

「記事は以下のように、publicなメソッドはcallだけにしておいてあとは全部privateにするタイプの、単機能を使い捨てで実行するだけのService Objectの話ですね」

# https://tech.medpeer.co.jp/entry/2019/05/08/180000 より
class HereMentionCreator
  delegate :channel, :creator, to: :message

  def self.call(message:)
    new(message: message).call
  end

  def initialize(message:)
    @message = message
  end

  def call
    members.each do |member|
      message.mentions.create!(to: member, chennel: channel)
    end
  end

  private

  attr_reader :message

  def members
    @members ||= channel.members.active - [creator]
  end
end

「そしてはてブを追いかけてたらちょうどMastodonのソースコードでも同じような感じでやってるのを見つけたりしました」

「Mastodonのもcallだけがpublicで、後は全部private↓」「こういうのはわかりやすくていいですね😋」

# https://github.com/tootsuite/mastodon/blob/master/app/services/notify_service.rb
class NotifyService < BaseService
  def call(recipient, activity)
    @recipient    = recipient
    @activity     = activity
    @notification = Notification.new(account: @recipient, activity: @activity)

    return if recipient.user.nil? || blocked?

    create_notification!
    push_notification! if @notification.browserable?
    push_to_conversation! if direct_message?
    send_email! if email_enabled?
  rescue ActiveRecord::RecordInvalid
    return
  end

  private

  def blocked_mention?
    FeedManager.instance.filter?(:mentions, @notification.mention.status, @recipient.id)
  end
...

「ゲストの皆さんにお伺いしますけど、こういうService Objectって使います?」「まさに今そういうのを使ってます☺️」「お〜やはり」

「ついでに伺いますけど、呼び出しのメソッド名は何にしてます?callとかexecuteとかperformとか流派があるようですけど」「クラス名を踏襲するという意味でcall派です😎」「意味のある名前を付ける派の人もいますけど、統一する方がわかりやすそうな気はしますね☺️」「たしかJavaだとperformを使ったりします」

runはだめでしょうか?」「runはService Objectだとちょっとニュアンスが違うかな〜: マルチスレッドで実行するイメージがあるので」「あ〜なるほど!」「Thread.run的な印象が強いかも」

「Service Objectは未だに統一見解がない感じですね😆」「Rubyだとcallが多いような印象ある」「後は上みたいにパラメータが増え過ぎたらParameter Object作ったりする、なんてのもありますね」

RailsでFacadeパターンを使う

# 同記事より
# app/facades/users_facade.rb
class UsersFacade
  attr_reader :current_user, :vip_presenter

  def initialize(current_user, vip_presenter=VipUsersPresenter)
    @current_user = current_user
    @vip_presenter = vip_presenter
  end

  def new_user
    User.new
  end

  def last_active_users
    @last_active_users ||= active_users.order(created_at: :desc).limit(10)
  end

  def vip_users
    @vip_users ||= vip_presenter.new(active_users.vip).users
  end

  def messages
    @messages ||= current_user.messages
  end

  private
  def active_users
    User.active
  end
end

つっつきボイス:「Service ObjectでもCommand的に書くのとFacade的に書くのがあるという話があったのでこういうのを探してみました」「Facadeって正直デザインパターンで名前付けるほどのものだろうかという気持ちはある🤣」「app/の下にservices/じゃなくてfacades/を置いて名前にFacadeと入っているところぐらいしか違わないっぽいですね」「utils/の下に置く何とかUtilityクラスをこうやってFacadeで書いているのは見たことあったかも」

Rails Trace: Railsのリクエスト/レスポンスをビジュアル表示(Ruby Weeklyより)


同サイトより


つっつきボイス:「左下の『Show Key』を押すと凡例が表示されます」「ほほう、コールスタックを追う的な?」「Metal呼んだりRack呼んだりしてる」「お、右にスクロールするし!結構長い」「Metal呼んだだけじゃまだまだ終わらないので☺️」

「Railsのリクエスト/レスポンスを旅するみたいな」「チャートの色をクリックすると機能とメソッドが表示されるし」「横に広がっている紫色がRackの層なのか: Rackのコンテキストがどこからどこまであるのかなんてのがわかるし」

「こういうリクエスト/レスポンスのイメージってどこかで意識しておくといいでしょうね☺️」「学習用にもよさそうですね🥰」

後で気が付きましたが、ビジュアル表示方法の解説記事とソースコードへのリンクも同サイトにありました。ReactでSVGを生成しているそうです。

その他Rails

つっつきボイス:「記事は普通っぽいんですが、オライリーのサイトというのが面白かったので拾ってみました☺️」「これは普通にアップグレード記事ですね: Railsに限りませんが、デュアルブートでやるのはベストプラクティスのひとつ」



つっつきボイス:「これははてブに上がってた記事ですね」「2018年の記事?」「あ、気が付かなかった😅」「大バズりした記事を定期的に広告としてはてブに浮かび上がらせてるからでしょうね」「見事釣られました🎣」

「無駄に長いコメントがだいたいよろしくないというのは確かに」「ところで皆さんはソースコードにコメントを書きたくない派ですか?」「いや〜ははは😅」「記事の『検討したけどやらなかったことをコメントにする』は、どこかでMatzが『Why notはソースコードでは表せない』と言ってたのにも通じていて、why notを表すのは大事

「ソースコードを読めばわかることはコメントに書く必要はないと思うけど、なぜこういうコードになったのかという理由はコメントで表すしかなさそうですよね☺️」「『普通ならpluckでやるけどなぜかmapじゃないと動かなかったのでこう書きました』とか😆」「『ここはActive Recordのバグらしいので回避のためにこう書きました』とか😆」「あと正規表現を究極にこじらせたときなんかも『こういうことをする正規表現です』ぐらいのコメントは欲しい😆」

Ruby

Rubyで関数合成

Thoughtbotの記事です。


thoughtbot.comより

# 同記事より
BENEFIT_COST_IN_CENTS = 1000 * 100
TAX_RATE = 0.4

subtract_benefit = ->(salary) { salary - BENEFIT_COST_IN_CENTS }
pay_tax = ->(salary) { salary * (1 - TAX_RATE) }

calculate_take_home_pay = subtract_benefit >> pay_tax
calculate_take_home_pay.call(SALARY_IN_CENTS) # => 840000.0

つっつきボイス:「Rubyでやらんでもええやん🤣」「compositionってどっち方面の言葉かなと思ったらやっぱり数学で言う合成関数みたいでした😆」

参考: 写像の合成 - Wikipedia

Procodile: Ruby製プロセスマネージャ


同サイトより

$ procodile start --foreground

16:13:41 system  | Procodile supervisor started with PID 24532
16:13:41 system  | Application root is /Users/swagman/Development/my-app
16:13:41 system  | Listening at /Users/swagman/Development/my-app/pids/procodile.sock
16:13:41 system  | Reloading configuration
16:13:41 web.1   | Started with PID 24548
16:13:41 worker.1| Started with PID 24549
16:13:41 worker.2| Started with PID 24550
16:13:41 cron.1  | Started with PID 24551
16:13:41 web.1   | => Puma starting in cluster mode...
16:13:42 web.1   | => * Version 3.12.0 (ruby 2.5.3), codename: Llamas in Pajamas
16:13:42 web.1   | => * Min threads: 5, max threads: 5
16:13:46 cron.1  | => Starting clock for 2 events: [ daily hourly ]
16:13:46 worker.1| => Starting worker... waiting for jobs
16:13:46 worker.2| => Starting worker... waiting for jobs
16:13:50 web.1   | => ::1 - - [26/Mar/2019:16:13:50 +0000] "GET /style.css HTTP/1.0" 302 - 0.2817
16:20:00 worker.1| => [3871] Beginning execution of job 3871 with DownloadLatestTweets
16:20:00 worker.1| => [3871] Downloaded 322 new tweets from 3 Twitter accounts
16:20:00 worker.1| => [3871] Finished processing

A brief introduction to Procodile from aTech Media on Vimeo.


つっつきボイス:「Procodileという名前の由来はワニの絵で丸わかりですね😆」「ぱっと見た感じforemanみたいなヤツ?」「ですです、リポジトリにそう書いてあって、バックグラウンドでもフォアグラウンドでも動くそうです」

「今さらですが、プロセスマネージャってどういうときに使うんでしょう?」「複数のプロセスを立ち上げないといけないものをまとめるときですね: サーバー以外にRedisなんかも含めて全部1個のコンテナの中で立ち上げたいときとか」

「ワーカーのプロセスを立ち上げ忘れたせいで非同期系の処理が実行されていなかった😇、というような事態を避けるためにプロセスマネージャをよく使います」「プロセスマネージャはワーカーを立ち上げることはもちろん、スーパバイザーとしても動作するので、ワーカーがout of memoryで死んだときに自動で再起動してくれたりと面倒を見てくれる」「なるほど!」「要するにスーパバイザーですね🧐」

参考: スーパーバイザー - Wikipedia

「Rubyだとforemanが定番なんでしょうか?」「Rubyならforemanだったり、Dockerだとsupervisorだったり↓」

Dockerでsupervisorを使う時によくハマる点まとめ

「あとは古き良きUnixではMonitなんてのもありますね」

「これまた昔にGODというRuby製のプロセス監視ツールもありましたね」「名前が強い!⛩」「プロセスマネージャはしょっちゅう使うものではありませんが、こんな感じでいろんなものがあります☺️」

scientist: GitHub製のクリティカルパスリファクタリング用ライブラリ(Ruby Weeklyより)

★が5000近くあります。

# 同リポジトリより
require "scientist"

class MyWidget
  def allows?(user)
    experiment = Scientist::Default.new "widget-permissions"
    experiment.use { model.check_user?(user).valid? } # 変更前のコード
    experiment.try { user.can?(:read, model) }        # 変更後のコード

    experiment.run
  end
end

つっつきボイス:「さいえんてぃすと?」「これもスゴい名前😆」「usetryを使って振る舞いやパフォーマンスを比較できるみたいです」「developmentモードとかtestモードで使う感じ」「コミットには入れないんでしょうね」「README、長っ😆」

「あ、末尾にいろんな言語のAlternativeがずらっとある!」「scientistっていう一般的なフレームワークがあるのかな?」「PHP版すらあるし」「今気づきましたが、これGitHub自身がやってるリポジトリなんですね😳」


同リポジトリより

「たぶん具体的には、リファクタリングの前と後で動作が変わってないかどうかをチェックするのかも?」「あ〜、それならtryとかrunも含めてしっくりくる😋」「compareなんてのもあるし」

「以下で言うとuseに既存のコード、tryにリファクタ後のコードを入れて、結果がcontrolcandidateに入って、それをcompareで比較するみたいな感じでやれるようだ」「リファクタリングテストのフレームワークと理解するとよさそう」「出力データの例がなぜかREADMEにないけど、だいたいそんな感じかなと☺️」

class MyWidget
  include Scientist

  def users
    science "users" do |e|
      e.use { User.all }         # Userインスタンスを返す
      e.try { UserService.list } # UserService::Userインスタンスを返す

      e.compare do |control, candidate|
        control.map(&:login) == candidate.map(&:login)
      end
    end
  end
end

後で気が付きましたが、他の言語のはRuby版のscientistから移植されたようです。以下のGitHub技術ブログに解説とともに整形済みグラフや出力サンプルっぽいものもありました。「副作用のあるコードへの利用は想定されていない」そうです。



github.blogより

# github.blogより
{
  context:
    repo: 3
    user: 1
  name: "repository.pullable-by"
  execution_order: ["candidate", "control"]
  candidate:
    duration: 0.0015689999999999999
    exception: nil
    value: true
  control:
    duration: 0.000735
    exception: nil
    value: false
}

その他Ruby


同サイトより

つっつきボイス:「前にも似たようなサイトを紹介したことがあったような気がするんですが、今後開催されるRuby関連のカンファレンスが開催期日順にずらっとリストアップされています(ほとんどは日本以外ですが😆)」「Balkan Rubyは毎年やってた気がする」 「RubyConf Colombiaって南米のコロンビアかな?」「大小さまざま☺️」



Ruby trunkより

リクエスト: Module#name_components

Foo::Bar.name.split('::').last   #=> "Bar"
# 上と同等の以下が欲しい
Foo::Bar.name_components         #=> "Bar"

つっつきボイス:「@mrknさんのリクエストですね」「名前空間を切り落としたコンポーネント名をシンボルで取れるメソッドがあるといいよね、みたいな」「コードを検査するようなコードを書くときに欲しいのは何となくわかる」


前編は以上です。

バックナンバー(2019年度第2四半期)

週刊Railsウォッチ(20190508-2/2後編)サロゲートキーのコスト、Cloud RunとLambdaの違い、miniredis、CSS Subgridほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h


CONTACT

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