- 開発
READ MORE
こんにちは、hachi8833です。だんだん季節というものがわからなくなってきました。
10月最後のRailsウォッチ、いってみましょう。
https://t.co/LV1PrVGy5Z kamipo さんと k0kubun くんはすごい人!!1
— SHIBATA Hiroshi (@hsbt) October 26, 2017
いよいよ来週に迫ったRuby World Conference 2017の1日目、11/1のプログラム最後で表彰式が行われます。@solnicさん、@kamipoさん、@k0kubunさん、おめでとうございます。
dry-rbシリーズやrom-rb(ROM: Ruby Object Mapper)シリーズは、これまでもRailsウォッチやTechRachoでときどき扱ってきましたが、どちらも@solnicさんの作だったんですね。
#RubyWorld Conference 2017の基調講演のタイトルが決定しました。https://t.co/MU155UEcyl
— RubyWorld Conference (@RubyWorldConf) October 26, 2017
# actionview/Rakefile
- system("npm run lint && phantomjs ../ci/phantomjs.js http://localhost:4567/")
+ system("npm run lint && bundle exec ruby ../ci/qunit-selenium-runner.rb http://localhost:4567/")
つっつきボイス: 「Chromeヘッドレスドライバの導入は先週のウォッチでも取り上げたんですが、Phantom.js廃止の一環ということだったんですね」「Phantom.js使う機会なかったナー」
「それにしてもどうして替えたんだろう?」「ググってみたらこんなのありますね↓」「今年の4月だったのか」
with_attached_*
を追加# activestorage/lib/active_storage/attached/macros.rb
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob
+ scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }
+
if dependent == :purge_later
before_destroy { public_send(name).purge_later }
end
ignored_columns
にシンボルでリストを渡すと正常に動かなかったのを修正何か変だなと思ったら、Rails公式ニュースのリンクが間違っていました。
# 修正前
self.ignored_columns = [:page_view] # `[]`のように動作
# 修正後
self.ignored_columns = [:page_view] # `['page_view']`のように動作
# actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee
- # Call beforeSend hook
- options.beforeSend?(xhr, options)
- # Send the request
+
+ unless options.beforeSend?(xhr, options)
+ return false
+
if xhr.readyState is XMLHttpRequest.OPENED
xhr.send(options.data)
- else
- fire(document, 'ajaxStop') # to be compatible with jQuery.ajax
prepareOptions = (options) ->
options.url = options.url or location.href
つっつきボイス: 「UJSあたりの動きってややこしくって: jQuery依存廃止のためにjquery-ujsがrails-ujsに替わって、さっきチェックしたら今年6月にRails 5.1で本体のAction Viewに組み込まれたんだそうです」
なおjquery-ujsのリポジトリは今もRailsの隣に残っていました。
factory_girl_railsもfactory_bot_railsに改名しました。
The name “Factory Girl” was confusing to some developers who encountered this library, and offensive or problematic to others. In October 2017 we renamed the library to “Factory Bot”.
NAME.mdより
どの辺がoffensiveかまでは説明されていません。
今後factory_girlとfactory_girl_railsはどちらも非推奨になってwarningが表示されますが、factory_botと機能的に違いはないようです。
つっつきボイス: 「機能違ってたら困るわなー」「girlという言葉がいわゆるポリティカル・コレクトネスの問題に引っかかったんでしょうかね」「Factory Girlって映画があったらしいけどそれと紛らわしいってことなのかな?」「gemの方はRolling StonesのFactory Girlって曲↓が元らしいって聞いたような」「Stonesにそんな曲あったってシラナカッター」
「うろ覚えですけど、factory_girlのissueで「この名前でStonesと映画のどっちを連想する?」みたいな質問があがってて速攻閉じられてたのを見た気がします」
https://www.youtube.com/watch?v=9UZmtqpc6wM
曲は一発で好きになりました。
Rails 5もサポートされています。
// remiprev/herより
// The response of GET /users/1
{ "id" : 1, "name" : "Tobias Fünke" }
// The response of GET /users
[{ "id" : 1, "name" : "Tobias Fünke" }]
「morimorihogeさんが使ってみてよさそうと言ってたので」「ほほう、RESTfulなroutingでJSONを取れるとな」
# 同記事より
require 'test_helper'
class OrderTest < ActiveSupport::TestCase
test "#last_ten eager loading" do
o = Order.new()
o.order_lines.build
o.order_lines.build
o.save!
orders = Order.last_ten
assert orders[0].association(:order_lines).loaded?
end
end
つっつきボイス: 「preloadされてるか、eager-loadingされてるかのテストか: よさげ」「これ翻訳してみますね」
以下のようなHTTPヘッダーを自動で追加してくれます。Rails 4/5の他にsinatraもサポートしているようです。★2300超え。
以前のウォッチでhttps://securityheaders.io/というチェックサービスを紹介しましたが、それとは別物のようです。
つっつきボイス: 「これ自分でやるのは大変なヤツだ」「デフォルト設定を与えるのが必須みたいですね」
つっつきボイス: 「DDD(ドメイン駆動設計)とあるので設計の話か」「割りといいこと書いてるかも: ときどきちょっとドキッとした」「それにしてもドメインという言葉って意味広すぎ」
15分の動画+コードサンプルです。
つっつきボイス: 「driftingruby.comってスクリーンキャストサイト知らなかったけど、エピソードリスト見るとそこそこ頑張ってる感じ」「ちゃんとコード例もページに載ってますね」「でないとみんな帰っちゃうから」
# 同記事より
class GraphqlController < ApplicationController
def execute
query = params[:query]
context = {
warden: warden,
viewer: viewer
}
result = RailsRelayAuthenticationSchema.execute(query, variables: variables, context: context)
render json: result
end
private
def viewer
warden.user || API::Viewer.new
end
def warden
request.env['warden']
end
end
つっつきボイス: 「Deviseの代わりにRack middlewareのWardenを直接使ってるのか」「Deviseだとプロジェクトには大きすぎることが多いから、だそうです」「これも翻訳しようかな」
つっつきボイス: 「CIビルドの所要時間とコードとテストの行数を入れると算出してくれるのか: 雑に入れてみたらこんな感じになった↓」「一人でプログラミングしている人とかにはそれなりの指標になりそう」
つっつきボイス: 「主に機械学習方面で使われているJupyter Notebookを使ってRailsのログをビジュアル化するというやつですね」「非開発者に渡して実行してもらうみたいな使い方できるかも」「JupyterはもともとPython用だったんですが、Ruby(iruby)とかいろんな言語でできるようになってて、実は結構好き: 勉強会に使ったりしてもよさそう」
なおirubyはSciRubyの一部です。
ActionCableのテストを書くときに使えそうです。
# palkan/action-cable-testingより
# spec/channels/chat_channel_spec.rb
require "rails_helper"
RSpec.describe ChatChannel, type: :channel do
before do
# initialize connection with identifiers
stub_connection user_id: user.id
end
it "rejects when no room id" do
subscribe
expect(subscription).to be_rejected
end
it "subscribes to a stream when room id is provided" do
subscribe(room_id: 42)
expect(subscription).to be_confirmed
expect(streams).to include("chat_42")
end
end
つっつきボイス: 「全然関係ないけど、RailsのActiveResourceってさっぱり見かけないナ」「そういえば」
抽象化のレベルや「単一責任の原則」を意識するなどの命名ノウハウ記事です。
つっつきボイス: 「英語圏の人が英語圏に向けて書いている記事ではありますが」「命名、いつも難しいっす」「コードは勢いに乗って書けても、命名は勢いでやるわけにいかないところがつらいところでしょうね」
「ベテラン開発者は命名の達人でもあるんでしょうか?」「命名というより、ピタリと合う概念に到達する方を気にしてるなー」
つっつきボイス: 「リストはまだ半分ぐらいしか埋まってませんが」「ActiveSupportを使わずに何とかしたい人っていうと、やっぱりSinatra?」「日付時刻系をActiveSupportなしでやるのは大変そう: このリストにも日付時刻系は載ってませんね」
# 同記事より
survey = Survey.create(name: "Numbers")
question = Question.create(text: "What is Planck's constant?")
Survey.transaction do
survey.update({ name: "", question_ids: [question.id] })
end
-- 同記事より
BEGIN
SELECT "questions".* FROM "questions" WHERE "questions"."id" = ...
SELECT "questions".* FROM "questions" INNER JOIN "questions_surveys" ON "questions"."id" = "questions_surveys"."question_id" WHERE "questions_surveys"."survey_id" = ...
INSERT INTO "questions_surveys" ("survey_id", "question_id") VALUES (..., ...)
COMMIT
つい先ほど公開された記事です。トランザクションの書き方に注意しないとアトミックでなくなってしまうことがあるという内容です。
PostgreSQL系記事の豊富なブログです。
-- 同記事より
CREATE DOMAIN wgs84 AS geometry CHECK (
-- a 2-dimensional point in our coord system
st_ndims(VALUE) = 2 AND
geometrytype(VALUE) = 'POINT'::text AND
st_srid(VALUE) = 4326
);
ドメインを使用すると、共通な制約を1箇所にまとめることができ、メンテナンスに便利です。 たとえば、E-mailアドレスを格納する列が複数のテーブルで使用されていて、アドレス構文の検証のためすべてが同一のCHECK制約を必要としているような場合です。 このような場合、各テーブルに個別に制約を設定するよりも、ドメインを定義してください。
PostgreSQL 9.2.4文書: CREATE DOMAINより
つっつきボイス: 「ポスグレのドメインってデータ型なのか」「やっぱりドメインって言葉意味広すぎ」
「今ググって見つけた記事↓がわかりやすかった」「お、ナベアツw」「なつい」
-- 上記事より
CREATE DOMAIN nabeatsu AS INTEGER
CHECK (
NOT (VALUE % 3 = 0 OR
substring(VALUE::text from '3') is not null)
);
ブロックパラメータ渡しが遅いのでlazyにしようというko1さんからの提案です。
# 遅い例
def block_yield
yield
end
def block_pass &b
# do something
block_yield(&b)
end
nil
Proc
オブジェクトを作成block_yield(&b)
などでプロックパラメータを他に渡すときはProc
オブジェクトを作成せず、ブロックの情報を渡すつっつきボイス: 「lazyにすると速くなる理由、これだけ見てもよくわからんなー」「関係あるかどうかわかりませんが、JRubyだとブロックパラメータの方が速いみたいですヨ↓」
JRubyだと&blockのほうが速いらしいんでRubyの&block速くなったらこのコード消したい https://t.co/idRB3TTDRD
— Ryuta Kamizono (@kamipo) October 5, 2017
「おお、RailsにJRuby用のコードが↓」「これはRailsには入れたくないコードでしょうね」
# https://github.com/rails/rails/blob/v5.1.4/activerecord/lib/active_record/attribute_methods/read.rb#L63-L73 より
# This method exists to avoid the expensive primary_key check internally, without
# breaking compatibility with the read_attribute API
if defined?(JRUBY_VERSION)
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
# https://github.com/jruby/jruby/pull/2562
def _read_attribute(attr_name, &block) # :nodoc
@attributes.fetch_value(attr_name.to_s, &block)
end
else
def _read_attribute(attr_name) # :nodoc:
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
end
end
つっつきボイス: 「何の話だろうと思ったら、おとといTechrachoでも翻訳を公開したRailsコードを改善する7つの素敵なGemにあった『マジックがあまり好きでない方はこのライブラリを使わなくてもよいでしょう』という一言に反論しているのか」
# 同記事より
# called once to patch in instrumentation
MethodProfiler.patch(SomeClass, [:method1, :method2], :name)
SomeClass.new.method1
SomeClass.new.method2
# called when starting profiling
MethodProfiler.start
result = MethodProfiler.stop
{
total_duration: 0.2,
name: {duration: 0.111, calls: 12}
}
つっつきボイス: 「ベンチマークでプロファイリングしやすくするパッチを書いたということみたいですね」「gemになってたらいいのに」
★3600超えです。
# minaドキュメントより
# config/deploy.rb
set :domain, 'flipstack.com'
set :user, 'flipstack'
set :deploy_to, '/var/www/flipstack.com'
set :repository, 'https://github.com/flipstack/flipstack.git'
task :deploy do
deploy do
# Put things that prepare the empty release folder here.
# Commands queued here will be run on a new release directory.
invoke :'git:clone'
invoke :'bundle:install'
# These are instructions to start the app after it's been prepared.
on :launch do
command %{touch tmp/restart.txt}
end
# This optional block defines how a broken release should be cleaned up.
on :clean do
command %{log "failed deployment"}
end
end
end
つっつきボイス: 「Capistrano的なデプロイツールみたいです」「SSHの使い方がCapistranoと違うのか」
# jnunemaker/httpartyより
# Use the class methods to get down to business quickly
response = HTTParty.get('http://api.stackexchange.com/2.2/questions?site=stackoverflow')
puts response.body, response.code, response.message, response.headers.inspect
# ドキュメントより
# Skips SSL certificate verification
class Client
include HTTParty
base_uri "https://example.com"
pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456"
def self.fetch
get("/resources", verify: false)
# You can also use something like:
# get("resources", verify_peer: false)
end
end
# rest-client/rest-clientより
>> response = RestClient.get 'http://example.com/resource'
=> <RestClient::Response 200 "<!doctype h...">
>> response.code
=> 200
>> response.cookies
=> {"Foo"=>"BAR", "QUUX"=>"QUUUUX"}
>> response.headers
=> {:content_type=>"text/html; charset=utf-8", :cache_control=>"private" ... }
>> response.body
=> "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n ..."
マイクロサービスとかクローラやりたい人向けのようです。
大急ぎでちょっとだけ動かしてみました。nanobox.ioにアカウントを作ってガイドにしたがって操作すると、出来合いのアプリ環境をローカルVM(VirtualBox)内に自動構築します。Railsであればnanobox run rails s
するとhttp://rails.dev:3000/でアプリが開きました。VMにはDockerも使えるけどまだおすすめしないそうです。
つっつきボイス: 「アカウントがあれば使えるみたいなので、でかいVMイメージを投げ合わずにリモート開発者と環境を完全に揃えたいときに便利なのかなと思いました」「rails.devでアクセスするために設定ツールがローカルDNSにちょっぴりパッチ当てますが」
以前から知られているgemですが一応。
つっつきボイス: 「以前参加したミートアップで『shoryukenのコミッタと戦う』みたいな話がちらっとあったのが気になってます: こわい人なのかな?」「issueがほとんど残ってないのは凄いかも」
# 同記事より
require 'socket'
puts "Starting the Server..................."
server = TCPServer.open(3000) # Server would listen on port 3000
loop{ # Servers run forever
client_connection = server.accept # Establish client connect connection
client_connection.puts(Time.now) # Send the time to the client
client_connection.puts("Closing the connection with #{client_connection}")
client_connection.close # Disconnect from the client
}
つっつきボイス: 「昔ながらのsocketプログラミングをやりたい人に」
1プロジェクトなら無料だそうです。
つっつきボイス: 「bundler_auditでも同じようなことできそうですね」「bundler-auditは自分で動かさないとアラート出ないですけどね」「CIで回せばいいかも」
つっつきボイス: 「図鑑、まだ2匹しかいない」「うーん、日本人には微妙なキャラデザイン」「萌え絵よりそれっぽくていいんじゃないですかね」「NoMethodErrorが攻撃力34.5で最強とは」
こういうカンファレンスがあることを初めて知りました。米国テキサス州オースチンで10/27に開催だそうです。って今日ですね。
つっつきボイス: 「すごい色遣いとフォント…読みづらいw」「2014年から毎年やっているそうですが、Matzが一度も参加していないのが珍しいです」
「今年参加のYehuda Katzさんって確かすごい人だったと思う」「Ember.js/Rails/jQuery/Rust、いろいろやってる…たしかに凄い」
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
コメントでも多くの人が別れを惜しんでいます。
つっつきボイス: 「さいなら~」
BPSのアプリチームが盛り上がってました。
つっつきボイス: 「目次ものすごく多い…システムプログラミング全制覇する気か…」
つっつきボイス: 「とりあえずアプリ登録してみたんですが、上みたいな適性テストをいくつか解いたら『Javaをやってはどうでしょう』と言われちゃいました」「ほほー、ところでこの問題はフィボナッチ数列ですな」「ほんとだ、開始値が違うだけだったのか(ワカラナカッタ)」
なお下の動画は分子ロボットではなく普通の体内のようです。
今週は以上です。
週刊Railsウォッチ(20171020)Rubyが来年で25周年、form objectでサニタイズ、コアなString解説本ほか
#form_tag
廃止決定のその後、deviseの5.1対応はこれから、ほかソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。