週刊Railsウォッチ(20181009)Rails 6の新機能:WYSIWYGエディタ「Action Text」、Rails 6の青写真スライド、Apache POIはスゴイほか

こんにちは、hachi8833です。休日があると平日が減ってむしろ大変です。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを社内有志でつっついたときの会話です👄

今回は「Railsウォッチ 公開つっつき会 第3回」の日でした。おかげさまで本編・懇親会ともに盛り上がりました🎊🍻。参加いただいた皆さま、ありがとうございます!🙇


つっつきボイス:「(開始前の雑談)Action Text出ましたね」「そうそう、今回はそれがトップです」「え、そんなのが出てた?!😳」「ではぼちぼち始めま〜す🎬」

最初Active Textと書き間違えたりしてました💦。

臨時ニュース: Rails 6で新機能: ブラウザ向けリッチテキストエディタTrixを取り入れた「Action Text」が導入(Rails公式ニュースより)

先週ぐらいにBasecampがTrixをリリースしたというDHHのツイート↓を見かけたのですが、その時点では様子がよくわからなかったので保留にしていました。TrixはBasecampでは前から使われていたらしく、公開間もないのに★が11000超えです。みんな欲しかったんでしょうね。

既存のブラウザ用リッチテキストエディタのほとんどがIE5.5のcontenteditableexecCommandのAPIを引きずっていたのを、新たにCoffeeScriptで作り直し(コンパイルはBladeを使用)、コードからの制御がうんとやりやすくなったということのようです。

<form …>
  <input id="x" type="hidden" name="content">
  <trix-editor input="x"></trix-editor>
</form>

つっつきボイス:「BPS社内Slackでも話題になってたヤツ」「どれ、動画↑をポチッと」「15分あるので飛ばし飛ばしで」「(動画を見つつ)scaffoldしてちょろちょろっと何か書いて…おぉ〜〜?!テキスト入力にいきなりデスクトップから画像をドラッグアンドドロップしてるし😋」「これ自力でやろうとすると面倒なヤツ」「DHH、GCPをGCSと言い間違えてたっぽい😆」「はい〜じゃこの辺で🎬」「😆」


同動画10:10より

# 同動画より post.rb
class Post < AppicationRecord
  has_rich_text :content
end
<!-- 同動画より _form.html.erb -->
<%= form_with(model: post, local: true) do |form| %>
...

<div class="field">
  <%= form.rich_text_area :content %>
</div>
...
<% end %>
<!-- 同動画より show.html.erb -->
...
<%= @post.content %>
...

「ところでこの手のWYSIWYGエディタ機能って使ったことあります?」「あります〜: そのときはWYSIWYGエディタで検索して出てきたものをもう片っ端から試したんですけど、結局どれを使ってもつらかった😭」「これ↓に載ってるCKEditor、自分も使ったな〜」「TinyMCEも」「結局どれもつらいんですよね~」

参考: 商用でも利用できる、イケてるWYSIWYGエディタ7選 2017年版 - ランサーズ(Lancers)エンジニアブログ

「この手の汎用的なWYSIWYGエディタってJavaScriptで書かれているんですけど、どれを使おうと結局アップロードのエンドポイントは自分でサーバー側に用意しないといけないんですよね😅」「それそれ!」「PHPのサンプルコードぐらいはあったりするけど当然そのまま使えるはずがないので、エディタ側の制約に合わせて一生懸命エンドポイントを作り込まないといけないし、UIを日本語化したり不要な機能をオンオフできるようにするconfigを書いたりとか、YouTube動画を埋め込むためにカスタムタグを作ったりとかしようとすると、面倒が無限に続く😇」「froala使ったときとかapplication.jsとかCSSとかをひたすら書きまくったし」「WYSIWYGやった人は誰もがそうなる」

「つまりAction Textがここまで簡単になったのはバックエンドがRailsという前提が置けるからですね」「ちょうどWordPressも今度WYSIWYGをリニューアルするとか言ってるけどあれも同じ」「例のGutenberg↓ですね」

参考: WordPressの新しいエディタGutenberg(グーテンベルク)の長短所について

「Action Textが使えるのはRails 6からか〜」「TrixそのものはRails前提?」「独立してるはずですが、CoffeeScriptで書かれます(コンパイルはBladeで)」「こーひーすくりぷとか〜😅、フロントエンジニアからめっちゃマサカリが飛んできそう⚔️」「私も普段から『CoffeeScript滅べ』って言ってるし」「自分もCoffeeScriptはもういいや」「(Trixのリポジトリを開きながら)var使ってる↓の見つけた😆」「🤣」「🤣」「CoffeeScript以前にES2015ですらない😆」「🤣」

# bascamp/trixより
var element = document.querySelector("trix-editor")
element.editor  // is a Trix.Editor instance

「ともあれTrixはRailsがなくても使えるということね」「だから★が11000超えなのかも」「Rails専用だとここまで★取れないでしょうね」

「まあ、ぺろっと貼るだけで使えるWYSIWYGエディタなんてものはこの世にありませんから😆」「🤣」「ちなみにWordPressのWYSIWYGが出力するHTMLって見たことあります?空の<div>タグとか、かなり物凄いのが出てくる🤯」「今度はWordPressにほこ先が😆」

「ついでにお見せすると、TechRachoのWordPressにはMarkdownプラグインを導入しています↓」「おぉ〜😊」「とは言え一部のスタイルでまだHTMLタグ必要ですが」「Markdownならローカルのエディタで書いてさっと貼り付けられるので(画像はしょうがないけど)」

「やっぱりMarkdownかなっ❤️」「プログラミングとかに興味のない人に普及しなさそうだけど😢」「WYSIWYGももう少し秩序のあるコードが書けるものだったらいいんですけどね〜ほんに☺️」

「果たしてAction Textはどうなるかな?」「フロント勢から『これだからRailsは』が飛んでくる予感が少々😆」「画像アップロードなんかが入ってくると設計的にフロントエンドとバックエンドのどっちの責務なのかが怪しくなってきそうで、そこが難しいっすね🤔: たとえば画像にカスタムタグのボタンを付けたりすると今度はサーバー側でもちょっとタグに手を加えてから保存するとか、やりたくなってくるわけですよ」「うんうん」

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

今回の公式情報が豊作だったので自分でコミットログを掘り起こさずに済みました。

credentialを複数環境でサポート

# 同PRより
rails credentials:edit --environment staging

現在の環境で特定のcredentialファイルが存在する場合はそれを優先する。
これによってproduction環境ではENV["RAILS_MASTER_KEY"]からマスターキーで取得したconfig/credentials/production.yml.encを最初にチェックし、またはconfig/credentials/production.keyを読み込む。
デフォルトの振る舞いはconfig.credentials.content_pathかconfig.credentials.key_pathで変更可能
credentials APIドキュメントより

# railties/lib/rails/application.rb#L445
    def credentials
-     @credentials ||= encrypted("config/credentials.yml.enc")
+     @credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path)
    end

つっつきボイス:「--environment stagingを指定できるようになったと」「ありそうでなかった」「credentialを環境で切り替えたいことがどのぐらいあるのかはさておいて😆」

「このcredentialって何でしたっけ?🤔」「そこに書かれているconfig/credentials.yml.encがcredentialファイルなんですが、鍵を暗号化してこのファイルに保存することでGitとかのリポジトリに登録できるようにする機能です🗝」「これで鍵変更の履歴も追えるようになる」

「サーバーのデータベースパスワードなどは、本来なら履歴を追えるGitリポジトリのような秘密を保てない場所に登録すべきではなくて、デプロイスクリプトとかAWSのKMSから引っ張ってくるべきなんですが、こういうのって地味に大変じゃないですか: 特にHerokuを使っている場合、サーバー側で任意のスクリプトを実行しようとするときに面倒なので、リポジトリに登録できて安全かつ楽に使えるようにしようというのがcredential機能ですね」「なるほど〜そういうノリでしたか😊」

パスワードをうっかりGitリポジトリに登録してしまい、後から消そうとしても以後のハッシュがごっそり変わってしまうのでチーム全員に迷惑がかかるというのはよくありますね。

参考: GitHub にパスワードとかセンシティブなファイルを push してしまったときの対処法 - Qiita

「鍵を環境変数に入れる手ももちろんあるんですけど、環境変数の容量も無限ではないんですよね: その点credentialならyamlに保存するのでサイズを気にしないで済むというメリットもあります😊」「その代り、このファイルは直接編集できない」「vimとかで開いたらあかんし、そもそも読めないという」「rails credentials:editコマンドで編集することで指定のエディタが開いて、暗号化と復号化を自動でやってくれる☺️」「なるほど、ちゃんとこれを使いましょうということですね☺️」

「個人的にはそれほど好きな機能ではないけど、この機能が欲しい人がいるのはワカル」「確かRails 5.2で入った機能でしたね」

Rails 5.2のcredential機能をKubernetesで使う(翻訳)

「なお、credentialの肝心のマスターキーが流出したらその瞬間に全滅する💥」「🌋」「credentialを使うと、たとえばチーム開発でメンバーが退職したら即マスターキーを変更しないといけなくなるので、そこが自分にはちょっと美しくないかな😅」「そういえば以前のウォッチでもその話になりましたね」「マスターキーをKMSに保存する手もありますけど」

Action Cableチャンネルの単体テストをサポート

ActionCable::Channel::TestCaseが新たに導入されます。

# actioncable/lib/action_cable/channel/test_case.rb#L21
+   module ChannelStub
+     def confirmed?
+       subscription_confirmation_sent?
+     end
+     def rejected?
+       subscription_rejected?
+     end
+     def stream_from(broadcasting, *)
+       streams << broadcasting
+     end
+     def stop_all_streams
+       @_streams = []
+     end
+     def streams
+       @_streams ||= []
+     end
+      # Make periodic timers no-op
+     def start_periodic_timers; end
+     alias stop_periodic_timers start_periodic_timers
+   end

つっつきボイス:「この間も似たようなヘルパーが導入されてなかったっけ?」「私もそんな気がしてたので後で調べます↓」

以前のウォッチの「ActionCableのテストに便利なアダプタを追加」だったようです。

「ActionCableを手動でデバッグするのは絶対ヤダ😝」「ActionCableって使うことあります?」「ちょろっと作りたいときにはActionCableは便利だと思いますね: 何か処理が終わったときに右上あたりにピコっと通知を表示したいなんてことはよくあるんですが、そういうシンプルな通知機能を作るときなんかにいい」「そのためにワーカースレッドを1つ使うことになりますが😆、管理画面ぐらいだったらユーザー数が少ないので問題なくやれる」

サポート外のストアにあるキャッシュキーを誤って使わないよう修正

# activerecord/lib/active_record/railtie.rb#L91
+   initializer "Check for cache versioning support" do
+     config.after_initialize do |app|
+       ActiveSupport.on_load(:active_record) do
+         if app.config.active_record.cache_versioning && Rails.cache
+           unless Rails.cache.class.try(:supports_cache_versioning?)
+             raise <<-end_error
+You're using a cache store that doesn't support native cache versioning.
+Your best option is to upgrade to a newer version of #{Rails.cache.class}
+that supports cache versioning (#{Rails.cache.class}.supports_cache_versioning? #=> true).
+ Next best, switch to a different cache store that does support cache versioning:
+https://guides.rubyonrails.org/caching_with_rails.html#cache-stores.
+ To keep using the current cache store, you can turn off cache versioning entirely:
+    config.active_record.cache_versioning = false
+end_error
+           end
+         end
+       end
+     end
+   end

つっつきボイス:「リサイクラブル!」「プルリク投げたschneemsさんは、TechRachoでも何度か翻訳記事出しています」「この設定↓が追加されるそうです」「しれっとマージされたっぽいけど、もしやバグ?😆」

config.active_record.cache_versioning = true

「あー、キャッシュエンジンがバージョニングに対応しているかどうかで挙動を変えないといけなかったってことか」「なるほど〜」「ファイルストアなのかmemcacheストアなのかとかmemoryストアなのかnullストアなのかで変えると」「それぞれにファイルが分かれてダックタイピングしてる」

# 同PRより
# activesupport/lib/active_support/cache/memory_store.rb
      # Advertise cache versioning support.
      def self.supports_cache_versioning?
        true
      end

「フレームワークが個別のキャッシュエンジンにどこまで対応するかというのはあるけど、Railsは割と積極的に対応する方ですね: MySQLとPostgreSQLとかも既に独自のものが入ってきてるぐらいだし、キャッシュもそういう感じで独自のものが入ってくると」「😃」

モデル生成に--migrations-pathsオプションを追加

# 同PRより
bin/rails g model Room capacity:integer --migrations-paths=db/kingston_migrate
      invoke  active_record
      create    db/kingston_migrate/20180830151055_create_rooms.rb

scaffoldとマイグレーションどちらでも使えるようです。

--migrations-pathsは8月末に#33760で追加されたばかりなので、どちらも新しいですね。
他にも--databaseオプションが#34021で追加されました。

# activerecord/lib/rails/generators/active_record/migration.rb#L26
        def db_migrate_path
-        if migrations_paths = options[:migrations_paths]
-          migrations_paths
-        elsif defined?(Rails.application) && Rails.application
-         Rails.application.config.paths["db/migrate"].to_ary.first
+         if defined?(Rails.application) && Rails.application
+           configured_migrate_path || default_migrate_path
          else
            "db/migrate"
          end
        end

+       def default_migrate_path
+         Rails.application.config.paths["db/migrate"].to_ary.first
+       end

+       def configured_migrate_path
+         return unless database = options[:database]
+         config = ActiveRecord::Base.configurations.configs_for(
+           env_name: Rails.env,
+           spec_name: database,
+         )
+         config&.migrations_paths
+       end

つっつきボイス:「マイグレーションパスを指定って…デフォルトでやろうよみんな😅」「db/migrate/以外にも置けるんですか」「デフォルトのマイグレーションフォルダ以外のものを使いたいときってあるのかな?」「どうしてもdb/migrateにだけは置きたくない人用だったりなんかしてね😆」

「何でそんな闇を作るんですか🤣」「マジでどんな使いみちが…?🤔」「db/migrateの下でフォルダを分けたいとか?」「うーん、あるとすれば、たとえばRailsアプリを複数の顧客に納品していて、顧客ごとに違うdb:migrateをやりたい、とか?」「あるいは、experimental用のマイグレーションパスを用意しておいて、masterにはexperimentalなコードをどんどんマージするけど、そのパスでマイグレーションしないとexperimentalなコードが発動しない、とか?」「うーん」「使い方間違ってる気がするけどな〜😅」

「下の方を見ると、マルチDBのdatabase.ymlに使えるんじゃ?みたいなコメントがありますね」「ははぁ、今のRailsは1マイグレーションで1つのDBにしか対応していないので、--dbと組み合わせて使えば複数データベースのマイグレーションができる、みたいな感じかな?その場合マイグレーションパスを変えないと破綻するし」「あ、確かに〜」「こんなことしないといけない状況って…とっほっほ〜😭」「自分ならridgepoleとか使うなっ😎」「ridgepole、以前のウォッチでも扱いましたね」

「おそらくですが、最近のRailsがマルチDBをサポートしたことの一環なんじゃないかな?」「あ、それならわかる😋」「マルチDBをサポートするならマイグレーションもマルチDBを使えないとね、ってことなのかも: 使うかどうかはともかく」「もうちょいスマートなやり方はありそうなので、Rails 6が出るまでにまた変わるかも😊」

productionでのAR属性の定義をlazyからeagerに変更

# activerecord/lib/active_record/railtie.rb#L140
+   initializer "active_record.define_attribute_methods" do |app|
+     config.after_initialize do
+       ActiveSupport.on_load(:active_record) do
+         descendants.each(&:define_attribute_methods) if app.config.eager_load
+       end
+     end
+   end

#29559↓でコントローラのアクションをeagerに定義したのと同じような要領でやったそうです。

# actionpack/lib/action_controller/railtie.rb#L80
    initializer "action_controller.eager_load_actions" do
      ActiveSupport.on_load(:after_initialize) do
        ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
      end
    end

つっつきボイス:「バグ修正でしょうか?」「パフォーマンス改善かなという気もするけど、productionモードなのに想定どおりじゃなかったからバグだったのかも」

「それにしてもeagerな処理になってるかどうかをどうやってテストするんだろうか?🤔」「テストコードを見るとassert_includes Post.instance_methods, :titleでeagerかどうかがわかるってことなのかな…」「いいのかそれで😆」「なぜこれでテストできているのかはわからないけどっ🤣Rubyの挙動的にそうなのかもしれない」

.psqlrcファイルを無視する-Xオプションを追加

# activejob/test/support/integration/adapters/queue_classic.rb#L3
   def start_workers
     uri = URI.parse(ENV["QC_DATABASE_URL"])
    user = uri.user || ENV["USER"]
    pass = uri.password
    db   = uri.path[1..-1]
-   %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database if exists "#{db}"' -U #{user} -t template1}
-  %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1}
+   %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -X -c 'drop database if exists "#{db}"' -U #{user} -t template1}
+   %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -X -c 'create database "#{db}"' -U #{user} -t template1}
    QC::Setup.create
     QC.default_conn_adapter.disconnect
     QC.default_conn_adapter = nil
     @pid = fork do
       worker = QC::Worker.new(q_name: "integration_tests")
       worker.start
     end

   rescue PG::ConnectionBad
     puts "Cannot run integration tests for queue_classic. To be able to run integration tests for queue_classic you need to install and start postgresql.\n"
     exit
   end

structure.sqlファイルも同様に-Xで無視されます(#34001)。


つっつきボイス:「database.ymlと.psqlrcの設定がかぶるのをどうにかする感じ?」「そのようです」「どれ、psql --helpしてみると…むむ、自分のマシンには今psqlが入ってない、なぜならDockerでやってるから😅」「こちらで見ると-X, --no-psqlrc do not read startup file (~/.psqlrc)となってました」「じゃやっぱりpsqlのオプションだ🎯: .psqlrcに起動時のシグネチャ表示設定とかあるとゴミが入って容易にバグるし」

ActiveJobのテストで実行ジョブの引数のサブセットをチェックできるようになった

# activejob/lib/active_job/test_helper.rb#L362
     def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil)
       expected = { job: job, args: args, at: at, queue: queue }.compact
       expected_args = prepare_args_for_assertion(expected)

       if block_given?
         original_enqueued_jobs_count = enqueued_jobs.count

         yield

         jobs = enqueued_jobs.drop(original_enqueued_jobs_count)
       else
         jobs = enqueued_jobs
       end
       matching_job = jobs.find do |enqueued_job|
        deserialized_job = deserialize_args_for_assertion(enqueued_job)
-       expected_args.all? { |key, value| value == deserialized_job[key] }
+       expected_args.all? do |key, value|
+         if value.respond_to?(:call)
+           value.call(deserialized_job[key])
+         else
+           value == deserialized_job[key]
+         end
+       end
      end
       assert matching_job, "No enqueued job found with #{expected}"
       instantiate_job(matching_job)
     end

つっつきボイス:「job_args↓で引数を取れるようになったとかそういう感じかな?」「上のif value.respond_to?(:call)↑があるからLambdaを取って、それをハッシュ的に使うようになったっぽい: ActiveJobのデータのとり方に関係あるんだと思いますが」「ちょっと理解を超越気味🤯」

# activejob/test/cases/test_helper_test.rb#L
  def test_assert_performed_with_selective_args_fails
    args = ->(job_args) do
      false
    end
     assert_raise ActiveSupport::TestCase::Assertion do
      assert_performed_with(job: MultipleKwargsJob, args: args) do
        MultipleKwargsJob.perform_later(argument2: { b: 2, a: 1 }, argument1: 1)
      end
    end
  end

Rails

スライド:「The Future of Rails 6 — Scalable by Default」(Rails公式ニュースより)

今年4月にピッツバーグで開催されたRailsConf 2018で発表されたスライドです。上のAction Textのプレスリリースにありました。


つっつきボイス:「Rails 6の青写真がだいたいここで説明されているようです: これまでウォッチでコミットを追いかけてきたこともあって、実際この通りに進んでいるものをいくつも見かけました」「(スライドをめくりながら)Rails 6ではスレッドベースのワーカーがデフォルトになるとか、マルチスレッドのテストがデフォルトになるとか」「ほぉ〜😳」「ここにもマルチデータベースやる宣言が出ているし、スケーラビリティがテーマになっている感」「database.ymlも書式が変わる↓」

# 従来
production:
  <<: *default
    database: db_production

production_animals:
  <<: *default
  database: db_animals_production

# 今後: 3-tier database.yml
production:
  primary: 
    <<: *default
      database: db_production

  animals:
    <<: *default
    database: db_animals_production

「さっきの#33994のマイグレーションパスの話もある」「で、こんなふうにモデルでコネクションを指定できる↓: おそらくApplicationModel的なところでこれを指定すれば個別のモデルにはいちいち書かなくていいはず」「マルチデータベースなら名前空間切るっしょ普通😎」

# app/model/animals_base.rb

class AnimalsBase < ActiveRecord::Base
  self.abstract_class = true

  establish_connection :animals
end

「で、マイグレーションでもestablish_connectionを指定できる↓: これを使うのがいいのか、switchpointみたいに実績のあるgemにするのがいいかというのはあるにしても」

path = Rails.root.to_s = "/db/animals_migrate"

desc "Migrate the cluster db"
task migrate: :environment do
  ActiveRecord::Migrator.migration_path = path
  ActiveRecord::Base.establish_connection(:animals)
  ActiveRecord::Taks::DatabaseTasks.migrate
  db_namespace["db:schema:dump"].invoke
end

「ちなみにswitch_pointはマスター/スレーブ形式の割とメジャーなマルチDBのgemですね: 以下のuse_switch_pointが今のestablish_connectionに相当する感じです」「ほほぉ〜👀」「switch_pointもこの間のウォッチで(略」

# switch_point READMEより
class Article < ActiveRecord::Base
  use_switch_point :blog
end

active_storage_validations gem(RubyFlowより)

# 同リポジトリより
class User < ApplicationRecord
  has_one_attached :avatar
  has_many_attached :photos

  validates :name, presence: true

  validates :avatar, attached: true, content_type: 'image/png'
  validates :photos, attached: true, content_type: ['image/png', 'image/jpg', 'image/jpeg']
end

以前のウォッチで取り上げたlog_analyzerと同じ作者です。


つっつきボイス:「こういうバリデーターってRails標準にもありそうだけど?」「自分が欲しくて作ったのかも: 入れ違いでRailsにも同じのができるか既にあるかもしれないので慌てて入れなくてもいいのかな🤔」「content_typeはセキュリティ問題につながることが多いから、こういうバリデーターは欲しい😍」

GitHubがRailsを3.2->5.2.1にアップグレード


同記事より

先週追加で貼った記事です。


つっつきボイス:「この記事読んでびっくりした~🤓」「3.0からかなと思ったら3.2だったという」「記事はあっさり目ですが苦労が偲ばれます」「もちろん何年もかけて準備してたでしょうね👍」

「何かこんなif文↓使ってるんですけど😅」「これも時間をかけて少しずつデプロイしてるからでしょうね: バージョンが変わっても同じコードで動くようにしておかないといけないだろうし、まあしょうがない😆」「きっとユーザーも一斉に切り替わるんじゃなくて、たとえば1/10のユーザーを人柱的に新しいバージョンに移して、様子を見ながらユーザーを少しずつ移すなんてこともしてるでしょうね」

# 同記事より
if GitHub.rails_3_2?
  ## 3.2 code (i.e. production a year and a half ago)
elsif GitHub.rails_4_2?
  # 4.2 code
else
  # all 5.0+ future code, ensuring we never accidentally
  # fall back into an old version going forward
end

「記事最後の教訓にも『勢いが大事』ってありますね🏄‍♀️」「だらだらアップグレードしていると永遠に終わらないし、その間にRailsのバージョンがまた1つ先に進んじゃったりするし😆」「😆」

remote_bootstrap_modal: 外部リンクをBootstrapのモーダルダイアログに読み込むgem(RubyFlowより)

Railsエンジン型式だそうです。

  1. アプリにBootstrapをインストールしておく
  2. Gemfileにこのgemを追加
  3. アプリのレイアウトファイルに<div id="modal-holder"></div>を追加(ここでモーダルがレンダリングされる)
  4. app/assets/javascripts/application.jsでjQueryよりも後に//= require remote_bootstrap_modalを追加
  5. respond_toに応答させるフォーマットを設定(:html:jsonなど)
  6. コントローラでrespond_modal_withに必要な引数を渡して呼び出す
  7. モーダルに読み込みたいリンクにdata: { modal: true }を渡す(例: link_to 'Customers', customers_path, class: 'btn btn-default', data: { modal: true }

つっつきボイス:「↓こういうことができるみたいです」「data: { modal: true }とすると指定したURLがこうやってモーダルの中でさくっと開くということね😋最初の方しか見てないけどやりたいことはだいたいワカル」


同記事より

「モーダル、使うかなぁ?」「たとえば単語の意味をWikipediaで引いてモーダルで表示したいなんてときに使えるかも: 実はこういうgemってあると地味に便利😍」「おぉ〜😋」

Railsでjoinするときの生SQLを見つつ最適化する(Hacklinesより)


つっつきボイス:「これに近い最適化はたまにやるかな: 割とよくあるヤツ」「最終的にexec_queryしてるし😆: まあ生SQLで書くと結局こうなるし」

# 同記事より
# Find Payment RMH
rmh_raw_query = "SELECT ri.name, ri.amount, inv.id FROM remittances ri LEFT JOIN invoices inv ON LOWER(ri.name) = LOWER(inv.number) WHERE ri.payment_id = #{payment.id} ORDER BY remittance_sequence_number ASC"
rmh_records = ActiveRecord::Base.connection.exec_query(rmh_raw_query).rows
payment_rmh = rmh_records.map{|rme| {name: rme[0], amount: rme[1].to_f.round(2),invoice_id: rme[2]}}

Dockerコンテナを複数プロジェクトで共有する(Hacklinesより)


つっつきボイス:「お、まるで今日自分が社内で発表した内容みたいだ」「今日たまたま見つけた記事なんですが、怖いくらいシンクロニシティを感じてしまいました」「複数のdocker-compose.ymlがあってそれらを連携させるという、まさに今日話した内容😆: そうそう、networks:にはこうやってexternal:オプション↓を付けないと参照できない」

# project_one/docker-compose.yml
version: '3.2'

networks:
  default:
    external:
      name: my_net

services:
  # ...

「今日話したときは、これ以外にconfigファイルを生成するときにenvsubstを使わないと2つのdocker-compose間での環境変数を同期できなくてつらかった話なんかもしたナ」「そうでしたね😋」

「docker-compose使います?」「大好きですね〜😋」「docker-composeを複数使い始めると、なぜKubernetesが必要になるのかがとってもよくわかってきますよ😭」「自分は複数使ってたっけか…?あ、1つあった気がする: 確かにつらいです😭」「Kubernetesで言うpodが、1つのdocker-composeに相当する感じで、Kubernetesならpod間の連携も定義できる💪」「なるほど〜」「こういう連携をやり始めるあたりが、いわゆるオーケストレーションツールが必要になってくる境目でしょうね: 個人的にはしばらくdocker-composeでもう少し頑張りたい気はするけど」「まだKubernetesに魂は売りたくないです〜🤣」「少なくともKubernetesクラスタを自前で管理するのは絶対やりたくない🤣」「🤣」

参考: Pods - Kubernetes
参考: オーケストレーション (コンピュータ) - Wikipedia

Ransackパラメータをsearch_form_forなしで作成する(Hacklinesより)

# 同記事より
# in index.html.erb

<%= search_form_for @q do |f| %>

  # Search if the name field contains...
  <%= f.label :name_cont %>
  <%= f.search_field :name_cont %>

  <%= f.submit %>
<% end %>

つっつきボイス:「あぁこのぐらいなら全然大した複雑さじゃないし: もっと極まったのがいくらでもあるし😎」「😆」「何か複雑なサンプルはと…これでも全然やさしい方だし↓: Ransackの本当の地獄はorとandが出てきてからでしょう、やっぱ💀」「😆」「😆」「そういえば以前のウォッチでも教わりました」「orやandが出てくるとJSONがネストし始めるので、JSONを自分で組み立てる気がなくなる感がヤバい😭」

参考: Complex Object Searching in Rails with Ransack | Lewis’ Blag

# 参考記事より
class Ticket < ActiveRecord::Base
  belongs_to :person

  def self.search(query = nil)
    if query
      params = {
        full_name_cont: query,
        subject_cont: query,
        id_eq: query
      }
    end

    ransack(params).result(distinct: true)
  end
end

週刊Railsウォッチ(20180702)Ruby 2.2メンテ正式終了、Ransackがつらくなるとき、書籍『Domain-Driven Rails』、GitHubの高可用MySQLほか

その他Rails


つっつきボイス:「このツイート↑が反響を呼んでました」「この間もそんな話になりましたけど、RSpecの書き方って最初に誰かが『これです!』って教えてくれないと本当に迷う😅」「そういえばmizchiさんがこの間出した良記事があるんですけど」「お、その記事この後に貼ってあります💪」「その記事にもあったように、新しいフレームワークなどが出たときに最初の時点できれいな雛形を書いてくれる人がいると、後の人はそれを追いかけるだけでよくなるのでとってもありがたい❤️」「最初が肝心」

参考: Everyday Rails – RSpecによるRailsテスト入門 Aaron Sumner 著 et al. [Leanpub PDF/iPad/Kindle]
参考: 【英語論文TIPS】意外に知らないet al.の書き方、読み方 | 英語猿

「et al.?」「上のEveryday Railsのリンクタイトルにあって気になったので: エトセトラ(etc.)のラテン語版みたいなやつだそうです」「ああ確かに論文ではよく見かけますね😋: ちょいとカッコつけてる感😆」「漢文の熟語みたいな感じで😆」

Ruby trunkより

提案: 配列に共通集合があるかどうかをチェックするArray#intersect?


つっつきボイス:「はてな付きのArray#intersect?だそうです」「ああ、(a1 & a2).any?のショートハンドね」「元々#intersect?ってなかったっけ?」「Setクラスの#intersect?はあるようなので、それのArray版が欲しいということみたい」「そうそう、Setなら&でできるんだった」

参考: instance method Set#intersect? (Ruby 2.5.0)

日本の新元号のUnicode合字どうするよ?


つっつきボイス:「martin先生からの//の次をRubyではどうしようかという問いかけです」「次の年号っていつ決まるんでしたっけ?」「改元の1か月前だった気がする」「マジで!😰」

参考: 新元号公表、改元1カ月前に システム改修対応促す  :日本経済新聞

「コードポイントに空きが1個だけあったような気がするけどどうだったかな…」「Macの文字パレットで見るとこんなんなってますけど↓」「くわっ😱」「空きがあるっちゃあるけど、の前後に半端に空きがあるし」「今後どうする気なんだろう😅」「まあ空きさえあれば実装はできますけどね」「コメントでnaruseさんが面白がってるのは、きっと開き直ってる😆」「『今後の展開が楽しみです』的な😆」

「元号が決まったら、例のwareki gemが即対応するだろうな」「wareki?そんなものがあったんですか😳」「皇紀も含めて日本の昔の元号もやたら充実してます↓」「何これ〜🤣」「漢数字も対応してます💪」「『作者は暦の専門家ではまったくありません』という一文が😆」「こんなの使うところあるんですか?」「特に官公庁は公式文書が元号ベースなので、普通に業務アプリでよく使われてますよ😋」

# warekiリポジトリより
# 和暦のパース (標準 Date インスタンス)
Date.parse("㍻一〇年 肆月 晦日")       # => #<Date: 1998-04-30 ...
Date.parse("安政七年 弥生")           # => #<Date: 1860-03-22 ...
Date.parse("元仁元年閏七月朔日")       # => #<Date: 1224-08-17 ...
Date.parse("萬延三年 5月 廿一日")     # => #<Date: 1862-06-18 ...
Date.parse("皇紀二千皕卌年")          # => #<Date: 1580-01-17 ...
Date.parse("正嘉元年 うるう3月 12日") # => #<Date: 1257-04-27 ...

# Wareki::Date を直接扱う場合
Date.today.to_wareki_date # => Wareki::Date インスタンス
Wareki::Date.parse("正嘉元年 うるう3月 12日") # => Wareki::Date インスタンス
Wareki::Date.new("明治", 8, 2, 1).to_date   # => 標準 Date インスタンス 1875-02-01

「そういえば省庁が順次西暦に切り替えると発表してましたね↓」「やるならぜひ一律でやって欲しい😅」

参考: 省庁データ、西暦に一本化=証明書など元号継続-政府:時事ドットコム

Ruby

Railsのエントリが多かったので今回は控えめです。

JRubyに移行する理由(Hacklinesより)


つっつきボイス:「JRubyのノウハウを持っている人がいるならやってもいいけど」「JRubyを使う理由というと、Javaを愛しているからでなければ、後はJavaのライブラリを使いたい場合かな」「それはありますね」「私も最初に触ったRailsはJRubyで動いてました☕️」

「Javaのライブラリで使いたいものと言えば、やっぱりApache POIでしょう↓」「POI?!」「丸めてポイ?」


同サイトより

「POIは信じられないほどよくできていて、世の中にあるExcelを操作できるJavaのライブラリとして最も優れているのがこれ」「知らなかった〜!😳」「POIはJavaの世界ではもう必須😎」「POIなら、人間にしか作れなさそうな神Excelですらグラフなんかも含めて作れるし」「マジで!?」「RailsとかでExcelを扱うgemは他にもいろいろありますけど、画像貼ったりグラフを作ったり、あとマクロも入れられるんだったかな?」「画像は実装したことある
」「しかも画像の位置調整や印刷のサイズ合わせまでできるので、Excelを印刷フォーマットと思っている人の要求にも応えられるほど再現性が高い」「言葉が出てこない…😳」

「POIってExcelの外部仕様を元に作ったんでしょうか?」「何でここまで作り込まれているのかは謎: こういうのが欲しい人が作ったんでしょうね」「RubyからJava経由でPOIを呼び出すこともできるけど、それだと遅いので、そういう人がJRubyを使いたいんじゃないかな🤔: 個人的には他にJRubyを使う理由が思いつかないけどっ😆」「POIはSIな人ならきっと知ってる😆」「とにかく信頼性というか実績が凄い: セル結合されているファイルとか、隠しワークシートなんかを正しく読めると確信できるのは、たぶん他にはない」「パスワードロックなんかも対応できそう」「Encryptionサポートがあるからできますね」「バイナリのExcelでも扱える」「えぇ〜!😳」「何しろ歴史が長いから(最初のバージョンが出たのは2001年)、XLSXじゃなくても扱える」「Excel 97以降が扱えるんですか!」「Excelより先にOSの期限が切れそう😅: Excel 97が動くWindowsって今あるんだろうか?」

「個人的には使わずに済めばそれに越したことはないけど😆、いざというときの最終手段としてPOIは知っておきたい」「いいこと聞いた😋」「きりがないので次行きましょう〜」

あなたがたぶん知らない5つのRuby技(Hacklinesより)


つっつきボイス:「このHash.newにブロックで渡すやつ↓、あまり使ったことないけど、キーと値を入れ替えるときか何かで使った気がする: まあこういうコードは正直書いて欲しくないけど😆」

# 同記事より
h = Hash.new { |h, k| h[k] = {} }

h[:layer_1]           # => {}
h[:layer_1][:layer_2] # => nil

「ああヒアドキュメントにメソッドチェインするヤツか↓: <<-SQL.gsub("\n", ' ').squishみたいな書き方ができる」「え、ここにメソッドチェインするの?😳」「squishはRailsのメソッドか」

# 同記事より
sql = <<-SQL.gsub("\n", ' ').squish
SELECT MIN(u.popularity)
FROM users u
WHERE
  u.created_at <= #{Time.now} AND u.created_at >= #{Time.now - 7.days}
SQL

puts sql

参考: Active_supportのString#squishで邪魔な改行文字や空白を綺麗にする - Bye Bye Moore

「ちなみにですが、ヒアドキュメントはあのRubyMineですらシンタックスハイライトがうまくいかなかったりします」「難易度高そう😭」

「最後のは単項演算子のオーバーライド↓はやって欲しくないヤツ」「Trueなんてクラス、Rubyにありましたっけ?」「あ、true.classするとTrueClassが出てくるから独自クラスか」

# 同記事より
class True
  def -@
    false
  end

  def +@
    true
   end
end

t = True.new

p -t
p +t

「まあRubyの隠し機能なんて、『Ruby隠し機能カルタ』なんてのが作れるぐらいいくらでもありますから😆」「😆」

GitLabコントリビュータにインタビュー(Hacklinesより)


つっつきボイス:「GitLabのWeb IDEが好きだそうです」「Full stack developer!」「強い😆」「そういえばGitLabのコミッターに日本人が1人いた気がする」

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

オンラインプロジェクト管理


同サイトより


つっつきボイス:「Backlogは最近BPS社内でも一部使われ始めてて、機能がシンプルでわかりやすい分、細かなことはできなかったりもする」「ところでBacklog使ってます?」「この間使いにくいって別のツールに移りました😝」「お、そうでした?」「そういう人はどういうツールを使ってます?Jiraとか?」「Asanaです」


同サイトより


同サイトより

「プロジェクト管理ツールもさまざまですけど、個人的には機能が少ないものが好き❤️」「GitHubがこれまで日本語化してこなかったので、日本のそうしたシェアをBacklogがかなり取っているらしいと聞きました」「Backlogはシェア大きくて、官公庁の仕事でよく使われています: おそらくポイントは日本語が100%とおって、日本語サポートがあって、あと円で決済できること」「それ重要!」「Redmineだと難しいと思う人もいそうですね」「Redmineは細かく設定できる分複雑なので、サーバーのおもりをする人も必要🤔: Redmineはチケット職人がいると運営がとてもスムーズだし(いないとつらいけど)、秩序立てて管理することを徹底できればとてもいい」


同サイトより

「BacklogはMarkdownに対応しているのがとりあえずありがたい(Redmineはアドオンが必要)」「Backlogは、メンバーに非エンジニアがいる比較的小さな案件で導入しやすいですね😋: BacklogにはGitのリポジトリ機能もあるけど、エンジニアには物足りないかもしれない」

「こういうツールは好みや案件との相性などもあるので一概には言えませんが、Backlogはその中では割といい線行っていると個人的には思います😋」

SQL

sqlfmt: 独断に基づくSQLフォーマッタ(DB Weeklyより)


同サイトより


つっつきボイス:「↓こうやって縦を揃えたい派っぽい」「あーなるほど👀」「書籍に印刷されるSQLにこういうスタイル多いですよね」「気持ちはわかるけど😆」


同記事より

「まあたとえばWHEREANDをどういうスタイルで配置する人が多いのかなというのはちょっと気になるところかも: ANDの後で改行する人と、ANDを次の行の頭に書く人とか」「ANDを行の頭に書くと他のSELECTINSERTと同じところに並ぶのがいや、という意見もありそうだし」「ありそう〜」

JavaScript

mizchiさんの「TypeScript入門以前ガイド」


つっつきボイス:「さっきもお話に出たmizchiさんのブログです」「そうそう、これはいい記事😍: 上から順に読んでいけばJavaScriptの大きな流れが押さえられるようになっている」「ミジンコから人間へ進化する過程というか😆」「最後の方でちょっと力尽きた感があるのがまた親しみが持てるし😆」「普段からTypeScript書いている人にはだいたい当たり前の話ですが、初めてTypeScriptを書く人やES2015をちゃんと書いたことのない人にはうってつけの力作❤️」

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

WordCamp: WordPressの巨大コミュニティによるイベント

イベントは既に終了していますが。
WordPressコミュニティはRubyコミュニティの数倍程度の規模で、かつ集まっている方々のWebデザインの水準が非常に高いと小耳に挟みました。


つっつきボイス:「WordPressのコミュニティは知らない世界」「デザイナーがたくさん集まっていて水準も高いらしいです」「あとSEO関係者も😆」「WordPressとパフォーマンスに関するスピーチ↓もある」「KUSANAGIみたいな高速WordPressホスティングサービスがあるぐらいなので、WordPressのパフォーマンスへの関心は高いと思う: 自分もWordPress高速に動かしたいし🚅」「TechRachoもこういうところに置けたらいいなと思ったりします😃」「今のTechRachoは?」「自前サーバーです」


同サイトより

「話は少し違いますけど、私たちのところではLOLIPOP!を使うことがありますね」「え、そのレンタルサーバー知らなかった💦」「昔からありますよ?」「普段AWSとさくらぐらいしか耳にしてなかった…😅」


同サイトより

AsciiDoc: パブリッシングを意識したマークアップ言語


同サイトより

拡張方法が仕様で定められていて、Markdownよりもレイアウトを細かく記述できるようです。Markdownユーザー向けというより、XMLを捨てたい人向け?

参考: AsciiDoc - Wikipedia
参考: AsciiDoc入門 - Qiita


つっつきボイス:「日本の企業ユーザーが多いらしいです」「へぇ、こういうポストMarkdown的なドキュメントエンジンだとSphinx↓の方が有名かと思ってた」「お、知りませんでした💦」


同サイトより

「Sphinxは歴史も長いし、LaTexも含めてひととおりのフォーマットに対応してるし↓、ドキュメントエンジンでいろんなフォーマットに出したいというとたいていSphinxという印象💪」「Pythonベースみたいですね」「それもたぶんあまり気にされてないかも: 自分は使ったことないし使うこともたぶんないと思うけど😆」


http://www.sphinx-doc.org/en/master/contents.htmlより

言語よろずの間

icecream: C++の分散コンパイラicecc

参考: Icecream - らるるの自宅と職場を往復する人生@それをすてるなんてとんでもない!


つっつきボイス:「babaさんの日報で知りました」「分散コンパイラは全然詳しくないなー: たぶんクラスタでどかんとビルドするんだろうけど」「ちなみにbabaはBPSのCTOで、超縦書↓というブラウザベースのEPUBビューアを主にやっているんですが、あれほどの規模になると分散コンパイルが必要なのは想像できるし、何しろそのためだけに超高速のSSDをマシンのPCI Expressに直接ぶっ刺してるほど: ディスクがどうしてもボトルネックになるから」「おー😳」「『コンパイルが30分で終わる❤️』って喜んでました😊」「(以下昔のビルド話)」

参考: PCI Express - Wikipedia

その他

全米のスマホで「大統領アラート」試験が実施

これが全米のスマホに一斉表示されたそうです。


つっつきボイス:「Facebookで知人がこれを見てびっくりしたと言ってたので」「これはびっくりするヤツ😨」「大統領アラート、何に使うんでしょうね?」「やっぱりミサイルが飛んできたときかしら🚀」

番外

太陽を周回する新天体「ゴブリン」が発見

Dwarfとなっていますが、質量はもしかすると地球並かそれ以上かも?


つっつきボイス:「Dwarf planet?」「惑星未満の準惑星ってことみたいです」「この軌道がめちゃめちゃアウトしていてスゴイ」「地球の近くまで来たら何か起きるかな?👽」「そのときボクら生きてるんでしょうかね😆」「公転周期どえらく長そうだし😆」「お、予定時間ピッタリに終わった🎉」「ではこのまま親睦会に移りましょう🍻」

参考: 準惑星 - Wikipedia
参考: 東京新聞:太陽との距離、海王星の80倍 新天体を米チーム発見:社会(TOKYO Web)


今回は以上です。公開つっつき終了後の親睦会もいつものように盛り上がりました🍻🍕。ご参加いただいた皆さま、お疲れさまでした&ありがとうございました!🙇

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

週刊Railsウォッチ(20181001)Railsアップグレード記事と各種支援ツール、CLI向けRubyワンライナー集、Rubyアプリをワンバイナリ化ほか

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

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

Rails公式ニュース

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

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言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ