Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ(20200330前編)Active Record Doctorで診断、Webpacker 5、GitHubのViewComponentとRails 6.1の3rd-party component frameworkほか

こんにちは、hachi8833です。

つっつき前ボイス:「このところフルリモートで自宅作業していると、つい人と口をきくのを忘れちゃいそうになるので、つっつき会参加します😆」「そんなに😆」「ゴミ捨て以外まったく外に出ませんでした😆」「ほぼパーフェクト😆」

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

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

今回はコミットリストから見繕いました。

PartialRendererをリファクタリング

今回のコミットリストでtenderloveさんのコミット数がやけに多いと思ったら、これでした。


つっつきボイス:「以下の❌マークの組み合わせはありえないので削除したということのようです」「お〜これは頑張った感ある💪」「パフォーマンス的には速くなった部分と遅くなった部分でプラマイゼロに近いようですが、コードはだいぶすっきりしたようです」

diffがかなり増えて申し訳ない。
PartialRendererが複雑でこのところつらかったので、意を決して手を入れることにした。
ビュー内部で誰かがrenderを呼ぶときにいろんな組み合わせのオプションが渡されるが、PartialRendererはそれらを一手に引き受けていたので、まずはいろんなシナリオを表にまとめてみた。

修正前はPartialRendererが❌も含めて全部やっていたので、ObjectRendererCollectionRendererを切り出した。
同コミットより

「今までPartialRendereroptionsで何でも受けられるようになってて組み合わせが爆発していたのを整理したということかな: renderにパーシャル名を渡す場合、コレクションを渡す場合、オブジェクトを渡す場合…みたいな」「renderにコレクションとオブジェクトを両方渡すとか全然意味わかんないし🤣」「それが❌の場合か」「パーシャル名を渡す場合は普通にレンダリング、パーシャル名とコレクションを渡す場合はコレクション内のオブジェクトをeachで回して云々、パーシャル名とオブジェクトを渡す場合はこう、コレクションだけを渡す場合はこう…というふうに上の表で整理したということですね」

「プルリクにも、optionsハッシュがいろんなケースに対応しすぎてたり使われない組み合わせをわざわざチェックしてたりしたみたいなことが書かれてますね↓」「そういう余分な処理を枝刈りしたということか」「こういうリファクタリングは全容を把握してる人じゃないと大変そう😲」「コミット数45は大きいですね」「これでいいんだろうかと首を傾げながら修正してそう」

名前でわかるように、CollectionRendererはコレクションのレンダリングを担当し、ObjectRendererはオブジェクトのレンダリングを担当する。これで各クラスの実装がシンプルになって理解しやすくなった(し、最適化もしやすくなったと思いたい)。そのためにスタックを少々複雑にせざるを得ず、前述のoptionsハッシュを分解してどのレンダラーで使うか決められるようにする必要もあった。
同コミットより

lookup_storeの互換性が壊れていたのを修正

# activesupport/lib/active_support/cache.rb#L57
      def lookup_store(store = nil, *parameters)
        case store
        when Symbol
          options = parameters.extract_options!
          retrieve_store_class(store).new(*parameters, **options)
+       when Array
+         lookup_store(*store)
        when nil
          ActiveSupport::Cache::MemoryStore.new
        else
          store
        end
      end

つっつきボイス:「これは@kamipoさんによる修正ですね」「lookup_storeって何だっけ?」「ああ、キャッシュストアに入ってるオブジェクトを引っ張ってくるのか」「Active Supportのキャッシュなんですね」

lookup_storeは、シングルトンメソッド的に任意の箇所でキャッシュストアの内容を引っ張ってくるのね」「つまりこのメソッドはシングルトンだからどこからでも呼べる」「なるほど」「Railsでコンフィグされていればそれを取れるし、されてなければメモリストアが取れるみたいな」

「Railsでは、こういうグローバルコンテキストから持ってくるみたいな書き方ってあんまりしませんけど、何かで必要になったら使うのかも🤔」

insert_allがenumを型キャストしない問題を修正

# activerecord/lib/active_record/insert_all.rb#L178

          def extract_types_from_columns_on(table_name, keys:)
            columns = connection.schema_cache.columns_hash(table_name)
            unknown_column = (keys - columns.keys).first
            raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column

-           keys.index_with { |key| connection.lookup_cast_type_from_column(columns[key]) }
+           keys.index_with { |key| model.type_for_attribute(key) }
          end

つっつきボイス:「insert_allがenumで型キャストしない、そういえばそうなってたような覚えが🤔」「まだinsert_all使ったことない😆」「これとかupsert_allってRails 6からでしたっけ?」「そうですね」

「たぶんバグかな」「今まではinsert_allでenumをサポートする気があんまりないのかと思ってました🤔」「お?」「だってcreated_atとかも作ってくれないですし😆」「あ〜そういうことか、insert_allって結構挙動違うのかも😳」「もしかすると最新のRails 6のmasterでは作るのかもしれませんけど、少なくとも自分のプロジェクトではcreated_atとかも全部書きましたし、そういうものなのかなと思ってました😆」「とりあえずAPIdockでinsertを見た感じでは、created_atとか設定しなさそうだけど🤔」「コールバックやバリデーションはトリガしないけど、enumをキャストしないとは書いてませんね😆」「どっちなんだろ😆」

単一のINSERT文で単一のレコードをインサートする。モデルはインスタンス化されず、Active Recordのコールバックやバリデーションもトリガされないが、渡された値はActive Recordの型キャストとシリアライズ処理を通る。
apidock.comより大意


「今回の修正の方向を今後も推し進めていったら、例のactiverecord_import gem↓とだんだん似てきたりして😆」「ありそう😆」「activerecord_importならやれるんだったかな…?あれはオブジェクト自体を渡すからやれると思います☺️」「insert_allではオブジェクトじゃなくてハッシュを渡しますから😆」「activerecord_import gemは結構使ってきたけど、ほぼActive Recordと同じように使えましたし、特に困ることもありませんでしたね😋」「その代わりactiverecord_importはレコードの数だけインスタンスを作るから、困るとすればそこぐらいかなと」

「activerecord_importでActive Recordのバリデーションをスキップしてもスピードが足りなくなったときに、Active Recordを使うのを諦めるという選択肢を取ったことありましたよ😆」「insert_allを使いたい場面ってだいたいパフォーマンスと隣り合わせのタイミングになってるはずだし」「Active Recordを使うのを諦めたときは、ああユニケージのアプローチは正しかったんだなって思いましたし😆」「ユニケージということは私に振ってます?😆」「つまりオブジェクトを作るとか無駄なことするより、テキスト処理でズゴっとやるのが一番速いなと😆」「まあ状況によってはそうかもしれませんね😆」「TSV作ってMySQLのトランザクションをオフにしてcopy fromで突っ込むと、ディスク読み出しと変わらないぐらい爆速になりましたし🚀」「🤣」

normalize_keysを高速化

# actionpack/lib/action_controller/renderer.rb#L103
    private
      def normalize_keys(defaults, env)
        new_env = {}
-       defaults.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
        env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
+
+       defaults.each_pair do |k, v|
+         key = rack_key_for(k)
+         new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
+       end
+
        new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
        new_env
      end

      RACK_KEY_TRANSLATION = {
        http_host:   "HTTP_HOST",
        https:       "HTTPS",
        method:      "REQUEST_METHOD",
        script_name: "SCRIPT_NAME",
        input:       "rack.input"
      }

-     IDENTITY = ->(_) { _ }
-
-     RACK_VALUE_TRANSLATION = {
-       https: ->(v) { v ? "on" : "off" },
-       method: ->(v) { -v.upcase },
-     }

      def rack_key_for(key)
        RACK_KEY_TRANSLATION[key] || key.to_s
      end

      def rack_value_for(key, value)
-       RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
+       case key
+       when :https
+         value ? "on" : "off"
+       when :method
+         -value.upcase
+       else
+         value
+       end
      end
  end

つっつきボイス:「1.24倍速くなってますね」「何のキーだろう?」「コントローラがリクエストするときのキーとかそのあたりかな🤔」「rack_value_forがあるからRackとかenvがらみっぽい」「プルリク↓に書いてあるように、毎回defaults.each_pairで全部引っ張ってたら遅いから、先にenv.each_pairしてからdefaults.each_pairで必要なものだけ設定するように修正したということか」「なるほど😋」

このPRでは以下の2つを行う:
* defaultsをすべて新しい環境ハッシュに設定してからenvのエントリでオーバーライドするのをやめて、envの値をすべて設定した後は既に設定済みのdefaultsの値の設定をスキップする。
* case文でlambdaのハッシュを切り替える
同PRより大意

ドキュメント修正

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): “DATEDIFF(updated_at, created_at)”. Non-attribute arguments will be disallowed in Rails 6.1. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().


つっつきボイス:「1つ目は、pluckのAPIドキュメントの書き方が古くて、そのとおりにしたらwarningが表示された↑ということみたいです」「ああなるほど、pluckに直接文字列を渡したらいかんと🚫」「Arel.sqlを通しなさいと」「へ〜、pluckにも文字列渡したらダメなのか😳」「orderとかに文字列渡してはいけないというのが入ったのは何となく覚えてますけどいつだったかな〜?🤔」「同じぐらいのタイミングでpluckもそうなった気がする🤔」「別々に対応する理由もなさそうですし☺️」「とにかくSQLインジェクション対策のためにはArel.sqlを使う必要がありますね」

# activerecord/lib/active_record/relation/calculations.rb#L177
-   #   Person.pluck('DATEDIFF(updated_at, created_at)')
+   #   Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))

後で調べるとRails 6から文字列を渡せなくなったんですね↓。


# guides/source/asset_pipeline.md#L44
Using the `--skip-sprockets` option will prevent Rails from adding
-them to your `Gemfile`, so if you later want to enable
-the asset pipeline you will have to add those gems to your `Gemfile`. Also,
+this gem, so if you later want to enable the asset pipeline
+you will have to add it to your `Gemfile` manually. Also,
creating an application with the `--skip-sprockets` option will generate
a slightly different `config/application.rb` file, with a require statement
for the sprockets railtie that is commented-out. You will have to remove
the comment operator on that line to later enable the asset pipeline:

「2つ目はアセットパイプラインのガイドの文面がいろいろイマイチだったので修正したということだそうです↑」「修正も英作文レベルみたい」「ついにCoffeeScriptの記述も消されてる😆」「さらばCoffeeScript👋」

Rails

Webpacker 5.0がリリース(RubyFlowより)

必要な最小バージョンがNode.js 10.13.0、Rails 5.2、Ruby 2.4になりました。


つっつきボイス:「Webpackの現在のバージョンは4.42.1ですし、WebpackerはWebpackとバージョン合わせる気なさそう」「Webpackも頑張って更新しないといけないうえにWebpackerまで気にしないといけないのって、どうもね…😭」「Webpackerの5を見た感じでは、必要なRubyやRailsやNodeのバージョンが上がったぐらいで、そんなに大きく変わってなさそうでした」「Multiple files per entryってどういう感じなのかな?🤔」「ファイル名が同じjsやcssごとにバンドルするようになったということのようで、以下で言うとhome.jsとhome.cssは同じhomeにバインドされるということみたいです」

# app/javascript/packs

accounts.js
application.js
home.js
accounts.css
home.css

extract_cssについて書かれてるけど、そもそもextract_cssが何をするのかを知らないと意味わからないでしょうね😆」「😆」「Webpackerのオプション以前にWebpackのプラグインとしてcss extract的なものがあるんですよ」「あ、そういうことですか😳」「Webpackで使うプラグインまでRailsと密結合しにいくのって、それはそれでひとつの未来かもしれないけど、それってどうなのかな〜😅」

config/webpacker.ymlのextract_cssオプションもtrueに設定しなければならない。
extract_cssは、出力ファイルをCSSパックごとに分割して生成するようWebpackに指示する。このオプションはdevelopment環境ではデフォルトでfalseなので、development環境でCSSバンドルを生成するには明示的にtrueに変更する必要がある。
同記事より

おそらく以下がそれのようです。

参考: webpack-contrib/mini-css-extract-plugin: Lightweight CSS extraction plugin

Webpackerのあり方

「もしかするとRailsとしてはそういう方向に持っていきたいのかも: Railsとして推奨するWebpackプラグインをバンドルして、みんなこれを出発点にしてくれみたいな🤔」「それありそうですね」「Railsって元々そういうところありますし、レールを敷きたいわけだし」「今まで使われてきたSASSがWebpackerでデフォルトで入っているあたりにそれを感じますね☺️」「そうそう、Railsが推奨するWebpackの機能は最初からバンドルして便利に使えるようにしとくから、という世界を目指している感じはちょっとある🤔」

「そのレールがいい感じのレールになるなら、Rails専門エンジニアにとってはWebpackerでいいかという気持ちになれるかも」「実際その辺のこと考えたくないですし😆」「考えたくない😆」「ゴリゴリのフロントエンド案件ならともかく、管理画面程度だったら、何を入れるかあれこれ考えるよりデフォルトの組み合わせでいこうぜみたいな」「よほど特殊なプラグインが組み込まれるとかでなければ」

「どっちにしろjavascript_pack_tagとかは自分たちでやらないといけませんし、manifest.jsonまでつながる何かを一気通貫で用意しとかないといけないというのは、そのとおりだと思います☺️」「そのあたりが事前に決まっていれば細かいエラーに遭わなくて済みますし」「その分フロントエンドエンジニアにはキラワレそうですけど😆」「まあWebpackerは剥がせるようになってますから☺️」「たしかに」

ViewComponent: GitHubのViewComponent(Ruby Weeklyより)

ViewComponentの設計哲学: 「驚き最小の原則」に従ってRailsへのシームレスな統合を目指す
同リポジトリより


ViewComponentは、React Componentsにインスパイアされたビューレンダリングクラスであり、データを受け取って出力安全なHTMLを返す。PresenterやDecoratorやViewModelパターンの進化系と思えばよい。
コンポーネントは、ビューのコードが再利用されるほとんどの場面で効果を発揮し、直接テストできるというメリットもある。
同リポジトリより

ViewComponentは、次に取り上げる「3rd-party component framework」とも互換性を保つそうです。

以下の動画が資料として紹介されていました。


つっつきボイス:「GitHubがガンガン使っているというViewComponentと、次の3rd-party component frameworkについて見落としてたので😅、ViewComponentがどういうものなのかとりあえず上に軽くまとめました」「文字どおりビューのコンポーネントか: inspired by React Componentとあるぐらいだから、Reactと同じぐらいのコンポーネント粒度ということなのかな🤔」「こういうふうに↓renderにコンポーネントを書いて使うと」「なるほど」

<!-- 同リポジトリより -->
<%= render(ModalComponent.new) do |component| %>
  <% component.with(:header) do %>
      Hello Jane
    <% end %>
  <% component.with(:body) do %>
    <p>Have a great day.</p>
  <% end %>
<% end %>

「ViewComponent、入れるのには相当抵抗あるけど、もしかするといいものなのかもしれない🤔」「ビューをコンポーネント単位で単体テストしたいというのが開発の動機だったのね」「たしかにこうなっていればコンポーネント単位で試験できる: フロントエンジニアはこういうのをフロントでコードを書いてテストするけど、同じことをRailsのレイヤでやろうとするとこうなるでしょうね🧐」「やろうとしてることは理解できるけど、これを導入するのは勇気が要るというか、フロントエンドに戻れなくなりそうではありますね🤔」「導入するなら今後すべてRailsでやるという不退転の決意が必要ということになりそう」

「Reactにインスパイアされたんだったら、ERBじゃないスタイルにして欲しかったなんて思ったり😆」「まあERB以外でもできるみたいだし😆」「content_tagとかtag.divとか書く↓みたいですけど、書きたくないというか、ここに生HTML書けるならワンチャンあるかなと思ったり😆」「プロジェクトメンバーが全員Railsエンジニアで、フロントエンドにあんまり興味ないという編成なら、ありかも☺️」「GitHubはそういう立ち位置なんでしょうね」

# 同リポジトリより
class TestComponentPreview < ViewComponent::Preview
  def with_default_title
    render(TestComponent.new(title: "Test component default"))
  end

  def with_long_title
    render(TestComponent.new(title: "This is a really long title to see how the component renders this"))
  end

  def with_content_block
    render(TestComponent.new(title: "This component accepts a block of content") do
      tag.div do
        content_tag(:span, "Hello")
      end
    end
  end
end

Q: ERB以外のテンプレート言語も使えるか?
A: ERB、haml、slimでテスト済みだが、ほとんどのRailsテンプレートハンドラーをサポートしているはず。
同リポジトリより

「おそらくGitHubはプロダクトが大きくなりすぎて、JSでテスト回すのがつらくなったのかも: ViewComponentならそれだけ読み込めばテストできるけど、フロントだとひととおり全部読み込まないとテストできないものが多いとか🤔」「次のトピックでそこに言及されてました↓」

Rails 6.1で入る「3rd-party component framework」とViewComponent

Rails 6.1で入る「3rd-party component framework」機能に今頃気づきましたが、これも主にViewComponentのためのようです。以下の2つのPRは昨年のです。

このプルリクでは、ViewComponentを含む「3rd-party component framework」のサポートが導入される。
GitHubには4000テンプレートがあるため、Railsビューで以下のつらみがある:
* テストがつらい: 現在のRailsではビューのテストを結合テストかシステムテストでやることを推進しているが、そのためビューだけをテストすればよいというわけにいかず、ルーティングやコントローラ層のオーバーヘッドがあるためにビューのフルテストがつらいことになっている。それによって同じパーシャルがビューごとに何度もテストされるので、ビューをDRYにしたメリットが帳消しになってしまう。
* カバレッジ: ビューのカバレッジが多くのRubyコードで正しく扱われていないためにテストの監査が難しく、テストスイートとのギャップが開いている。
* データフロー: ビューでは、オブジェクトでのメソッド宣言と異なり、受け取ることを期待する値が宣言されない。そのため、レンダリングに必要なコンテキストを判定するのが難しくなり、1つのビューを複数のコンテキストで使い回すと微妙なバグをしょっちゅう踏むようになる。
* 標準的なRubyコードでもつらい: GitHubのビューは、Rubyクラスで期待される標準的なコード品質であっても、ほとんどがメソッドが長いだの条件ネストが深いだのでfailする。
同PRより大意


ViewComponentのメリット:
* ビューを単体テストできる。単体テストならだいたい25ミリ秒、結合テストでも最大6秒。
* カバレッジ: 少なくともカバレッジツールと一部互換性があり、SimpleCovでは一部うまくいっている。
* データフロー: コンポーネントのレンダリングに必要なコンテキストを明確に定義できるので、パーシャルよりも再利用が楽になった。
同PRより

つっつきボイス:「GitHubのビューテンプレートが4000超えてて、テストが重くてつらくてしょうがなかったそうです」「上の『ルーティングやコントローラ層のオーバーヘッドがあるためにビューのフルテストがつらいことになっている』とか、きっとフロントエンド勢から『フロントとAPIの構成にしとけばよかったのに、密結合してるからそういうことになるんじゃぁ😇』って言われそう😆」「😆」「『そんな無理しなくてもFirebaseでも使えば、フロントエンドでテスト書いてテストできるよ😋』って言われたりして🤣」「🤣」

「カバレッジを改善したいという意図、理解できる」「これもフロント勢に言わせれば…(ryってなりそうですけど😆」

「まあRailsのビューにもうひとつ別のソリューションが入ることは悪くないと思いますね☺️」「言えてる」「3rd-party component frameworkでやれば新しい言語覚えないで済むし😆」「ただGitHubがもし仮に最初からやり直せるとしたら、果たしてViewComponentを選んだだろうかって思ったり🤣」「それな🤣」「歴史的な理由でこれになったんじゃないかと😆」

「もしかすると3rd-party component frameworkって、いわゆるActiveとかActionが名前に付かないコンポーネントを導入できるという意味なんだろうか??🤔」「今でもgemを使えば入れられますし😆」「そういえば何が違うんだろう?」「そういう位置づけは詳しく見ないとわからないな〜🤔」

「とりあえず#36388の『いいね👍』数がめちゃくちゃ多いし期待されてそうではありますね」「Railsの最大手ユーザーのひとつであるGitHubが使ってるから、という勢いで押されてたりして😆」「サードパーティといいつつ今のところGitHubぐらいしかなさそうですけど😆」「とりあえずViewComponentそのものは、コンポーネント単位でテストできますし、自分は割とキライじゃないですね👍」「今の世の中でスクラッチからRailsプロジェクトを立ち上げるときに使うかというと、ちょっと考えますけど😆」

「以下もViewComponent的なものらしいです↓」「コンポーネントを組み合わせてビューを作るという考え方は、それこそいにしえの昔からあるヤツですね: それこそPHPでSymfonyのバージョン0.x系使ってた頃から、コンポーネントを作ってその中にコンポーネントスロットを作ったりとか、そういう名前でありましたし🧐」「いわゆるビューモデルというヤツ」「概念としては新しくない」「まあそんなにキレイに作れるかどうかはまた別😆」

参考: ビュー・モデル - Wikipedia

🌟Active Record Doctor: ARの問題を診断🌟(Ruby Weeklyより)

Active Record Doctorでやれること:

  • インデックス化されてない外部キーのインデックス化
  • 不要不急なインデックスを検出する
  • 外部キー制約付け忘れを検出する
  • 未定義テーブルを参照しているモデルを検出する
  • uniqueインデックスがないuniquenessバリデーションを検出する
  • non-NULL制約付け忘れを検出する
  • 存在バリデーション付け忘れを検出する
  • booleanカラムに誤って付けられた存在バリデーションを検出する

つっつきボイス:「Active Record周りをチェックしてくれるのね😋」「なるほど😋」「これは何も考えずに入れておいていいgemかな👍」「CIに入れてもよさそうですね😋」「指摘もらって、それが正しいかどうか確認するだけでも意義ありそう」「単にやり忘れてたとか、そのうちやるつもりでそのままになってたなんてことはいつでもありますし」「外部キーを付けることも面倒で忘れやすい😆」「こういうのに怒られたらしょうがないという気持ちになれますし」

「uniquenessバリデーションあるのにuniqueインデックスが張られてないって😆」「ありがち😆」「もう正しさしかない😆」「う、やっちゃってるかも😅」「モデルのバリデーションって、一種気休めというか、本質的じゃないですし」「uniquenessチェックで毎回SELECTするのにuniqueインデックスないのはヤバい😆」「本当に信じられるのはunique制約エラーぐらい: create_or_find_byというメソッドがRailsに生えてるぐらいですし」「下手するとそこでINSERTが詰まる😆」

久しぶりに🌟を進呈いたします。おめでとうございます🎉。

Facadeパターンでパフォーマンスとメンテナンス性を改善(Ruby Weeklyより)

# 同記事より
module Books
  class IndexFacade
    attr_reader :books, :params, :user

    def initialize(user:, params:)
      @params = params
      @user   = user
      @books  = user.books
    end

    def filtered_books
      @filtered_books ||= begin
        scope = if query.present?
                  books.where('name ILIKE ?', "%#{query}%")
                elsif isbn.present?
                  books.where(isbn: isbn)
                else
                  books
                end

        scope.order(created_at: :desc).page(params[:page])
      end
    end

    def recommended
      # ネストしたfacadeがここにある。
      # ビューの`Recommended Books`の責務は1つなので
      # これを切り出すことでカプセル化とテストしやすさが改善される
      @recommended ||= Books::RecommendedFacade.new(
        books: books,
        user: user
      )
    end

    private

    def query
      @query ||= params[:query]
    end

    def isbn
      @isbn ||= params[:isbn]
    end
  end
end

つっつきボイス:「普通のFacadeパターンかなと思いつつ」「普通にFacadeパターンですね😆」

「Facadeって、GoFのデザインパターンの中でも『これってパターンというほどのものかしら、ただの切り出しでは😆?』という気持ちになりますね」「😆」「『ここはFacadeパターンでやりました』とか言うとスゴいことやってるような響きありますけど😆」「オブジェクト指向というほどでもない感☺️」

[保存版]人間が読んで理解できるデザインパターン解説#2: 構造系(翻訳)

その他Rails


つっつきボイス:「『ロード・オブ・ザ・リング』のセリフなどをいろいろもじってたのが楽しかったので🧝‍♂️」「普通にRuboCopでレガシーコードと戦う記事💣」「3306 files inspected, 12418 offenses detectedとか見るとドキドキする😆」「やべえ😆」

「Todo or not Todo😆」「You shall not passはガンダルフの『ここは通さぬ!』↓ですね😆」「😆」

参考: ガンダルフ - Wikipedia

つっつきボイス:「*_previously_changed?きたー😆」「dirtyってどこまで使えるのかドキドキしちゃう😆」「from: nil, to: "Tesla"とか書けるようになるとは」

# 同記事より
car = Car.new
car.changed?                                      # => false
car.company = "Tesla"
car.changed?                                      # => true
car.company_changed?                              # => true
car.company_changed?(from: nil, to: "Tesla")      # => true

「何のpreviousなんだろ?🤔」「値がnilから"Tesla"に変わったということか」「dirty絡みっていろんなメソッドがあって覚えにくい😆」「changed?は保存するとfalseに変わるようになったんですね↓」「サンプルコードでfrom:to:付けても付けなくてもbooleanが同じだと違いがわからん😆」「ちょい見づらい😆」「reloadするとクリアされるということか」「reloadに対応するのは無理そうかな☺️」

# 同記事より
car.save
car.changed?         # => false
car.company_changed? # => false

car.reload
car.company_previously_changed?                               # => false
car.company_previously_changed?(from: nil, to: "Tesla")       # => false

「自分はDocker for Windowsは普通に使う分には今のところそんなに苦労してないかな〜😋」


「チュートリアルにさらに解説動画があるという😆」「Railsチュートリアル大きいから😋」「こうやって裾野が広がっていくのはいいですね👍」


前編は以上です。

バックナンバー(2020年度第1四半期)

週刊Railsウォッチ(20200317後編)Strangler Figパターンでリファクタリング、ペアプロ実践記事、イミュータブルデータモデルほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h


CONTACT

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