- Ruby / Rails関連
週刊Railsウォッチ(20180820)Railsで構築されたサイト40選、Deviseはつらいよ、ARのスコープとクラスメソッドの使い分けほか
こんにちは、hachi8833です。Matzにっきを最初から読みふけってたら完璧に寝不足になってしまいました。
つっつきボイス:「お、例のMatzにっき、この間404になってなかったっけ?」「その後復旧してました: ここのtDiaryのナビゲーションがつらくて、最も最初の月にたどり着くのに何回もクリックしないといけなかったり😭」「😆」「最初が2003年なのでまだRailsも世に登場してなかった頃でした」
スクレイピングしてローカルで読もうかとも思いましたが負荷かけるのがコワイので、ブラウザで月ごとに気長にSave asし始めてます🐢。
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを社内有志でつっついたときの会話です👄
⚓お知らせ: 第2回「週刊Railsウォッチ 公開つっつき会」開催
初回の8/2に続き、「週刊Railsウォッチ 公開つっつき会 第2回」を9月6日(木)19:30〜より開催いたします。詳しくは上のリンクでご覧ください。皆さまのご参加をお待ちしております🙇🙇。
もりもりさんこないだ会ったけど、すごくわかりやすい説明と話し方をしてくれる方だった。 https://t.co/Z9h6JwtU2Q
— すろっくさん (@srockstyle) August 14, 2018
⚓Rails: 先週の改修(Rails公式ニュースより)
⚓ActiveStorageのエラーハンドリングを改善
issue #33157の方がわかりやすいかも?
わかりにくかったエラー
NameError: Cannot loadRails.config.active_storage.service
: wrong constant name diskService
#33157より
# activestorage/lib/active_storage/service/configurator.rb#L27
def resolve(class_name)
- require "active_storage/service/#{class_name.to_s.underscore}_service"
+ ActiveStorage::Service.const_get(:"#{class_name}Service")
+ ActiveStorage::Service.const_get(:"#{class_name.classify}Service")
+ rescue LoadError
+ raise "Missing service adapter for #{class_name.inspect}"
end
つっつきボイス:「"#{class_name}Service"
が"#{class_name.classify}Service"
に...?🤔あー大文字小文字をクラス名のスタイルにするメソッドか」「言葉どおりの『分類』ではなかったんですね💦」
参考: Ruby on Rails 5.2 / ActiveSupport::Inflector#classify
— DevDocs
# devdocs.ioより
classify('ham_and_eggs') # => "HamAndEgg"
classify('posts') # => "Post"
⚓キャッシュのフェッチでnil
をスキップするようになった
# activesupport/lib/active_support/cache.rb#L701
def save_block_result_to_cache(name, options)
result = instrument(:generate, name, options) do
yield(name)
end
- write(name, result, options)
+ write(name, result, options) unless result.nil? && options[:skip_nil]
result
end
つっつきボイス:「今までは結果がnil
の場合もキャッシュに保存されて、キャッシュがexpireするまで残っちゃってたのか💡」「で、今後はskip_nil: true
というオプションを指定すれば、結果がnil
の場合はキャッシュしないようになると👍: わかりみ」
⚓ネストした属性でextendしたときにbuild
が呼ばれるように修正
これもissue #33389の方がわかりやすいかも。
# activerecord/lib/active_record/nested_attributes.rb#L503
unless reject_new_record?(association_name, attributes)
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
+ association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
end
つっつきボイス:「NestedAttributes
は普段使わないなー: そこにも載っているaccepts_nested_attributes_for
はいつ消えるんだろうって思ったり」「それ何でしたっけ?」「あ、これ実は要らないんじゃないかっていう説が前からあってですねー、典型的なパターンから外れてカスタマイズし始めると途端に破綻するヤツ」「へー!」「一応Railsの標準機能ではあるし、使われているのも見かけるんですが、たとえば順序を変えようとしたりするとすぐフォームが泥臭くなっちゃうんで自分はあまり好きでないです😩」「ストンとはまるところだけにしとけってことですね」「カスタマイズなしで作れる管理画面とか、後はSPAなんかでフォームを自分でビルドするときとかでしょうね😎」
参考: #method-i-accepts_nested_attributes_for
# api.rubyonrails.orgより
class Member < ActiveRecord::Base
has_one :avatar
accepts_nested_attributes_for :avatar
def avatar
super || build_avatar(width: 200)
end
end
member = Member.new
member.avatar_attributes = {icon: 'sad'}
member.avatar.width # => 200
参考: 複数の子レコードを作成・更新する. accepts_nested_attributes_for
- Qiita
⚓Timeカラムの精度を改善
以下はReferences to changes in Rails 5.2から見繕いました。
# activemodel/lib/active_model/type/time.rb#L28
private
def cast_value(value)
- return value unless value.is_a?(::String)
+ return apply_seconds_precision(value) unless value.is_a?(::String)
return if value.empty?
- if value.start_with?("2000-01-01")
- dummy_time_value = value
- else
- dummy_time_value = "2000-01-01 #{value}"
- end
+ dummy_time_value = value.sub(/\A(\d\d\d\d-\d\d-\d\d |)/, "2000-01-01 ")
fast_string_to_time(dummy_time_value) || begin
time_hash = ::Date._parse(dummy_time_value)
return if time_hash[:hour].nil?
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
end
end
つっつきボイス:「precisionが指定できるようになったと」「quoted_なんちゃら
のquotedって?」「そりゃ引用符""
で囲む↓ってことでしょうね😆」「深読みしなくてよかったのか💦」「それにしてもActiveModelの中に2000-01-01
みたいな日付がハードコードされてるのって何なんだろう?🤔テストコードならまだしも」
# activerecord/test/cases/adapters/sqlite3/quoting_test.rb#L58
+ def test_quoted_time_normalizes_date_qualified_time
+ value = ::Time.utc(2018, 3, 11, 12, 30, 0, 999999)
+ type = ActiveRecord::Type::Time.new
+ assert_equal "'2000-01-01 12:30:00.999999'", @conn.quote(type.serialize(value))
+ end
quoted company: 上場会社
⚓セッションやcookieでのto_h
とto_hash
の挙動を揃えた
# actionpack/lib/action_dispatch/middleware/cookies.rb#L341
+ # Returns the cookies as Hash.
+ alias :to_hash :to_h
+
つっつきボイス:「to_h
とto_hash
の挙動が違ってた?」「ActionDispatchのSession::Request
にはto_hash
があったけどto_h
がなくて、Request:: CookieJar
にはto_h
があったけどto_hash
がなかった、ってことみたい」「ははぁ食い違ってたのか」「この記事↓ではto_h
とto_hash
の違いを説明してたけど、それとは別の話だったか」「確かにセッションとcookieって近いところにあるからこれが違ってたらイヤだなー😤」
⚓リレーションをmerge
したときにINNER JOIN
が変わらないようにした
# activerecord/lib/active_record/associations/join_dependency.rb#L107
- def join_constraints(outer_joins, join_type)
+ def join_constraints(joins_to_add, join_type)
joins = join_root.children.flat_map { |child|
make_join_constraints(join_root, child, join_type)
}
- joins.concat outer_joins.flat_map { |oj|
+ joins.concat joins_to_add.flat_map { |oj|
if join_root.match? oj.join_root
walk join_root, oj.join_root
else
oj.join_root.children.flat_map { |child|
- make_outer_joins oj.join_root, child
+ make_join_constraints(oj.join_root, child, join_type)
}
end
}
end
2016年11月のPRですが、マージされるまで半年以上かかってました。「INNER JOINが変わるのは仕様かも?」みたいな議論を経ています。
# 同PRより
Author.joins(:posts).merge(Post.joins(:comments))
# 期待
#=> SELECT ... INNER JOIN posts ON... LEFT OUTER JOIN comments ON...
実際
#=>SELECT ... INNER JOIN posts ON... INNER JOIN comments ON....
つっつきボイス:「確かに上の書き方ならINNER JOINにならないとおかしいのでわかるけど、元のが正規の挙動だと思ってやってた人いそう」「😅」「こういうのってto_sql
で確かめながら使うし、『こうやったらLEFT JOINできるのか!やったね💪』と思って使ってたらbreaking changeになったり」「これは完全にbreaking changesですね: マージに時間かかるのも無理ないし」
⚓Rails
⚓simple_calendar: Rails向けカレンダー
- サイト: Simple calendar by excid3
- リポジトリ: excid3/simple_calendar
つっつきボイス:「最近kazzさんがカレンダーの設計と実装で頭抱えてたので」「ああーそういえば😆😆」「まーカレンダーは自力で実装するもんじゃないよなー😆」「表示はともかくモデルの設計で手こずってたようです」「カレンダーの中身をどこまで自由にさせるかで全然変わりますしね」「項目が増えたら...
にするとかね😆」
「このカレンダーはそこそこ使いやすそうっすね: このdo
ブロックをeach
的に回してその中にやりたいことを書く↓みたいな」
<!-- 同記事より -->
<%= month_calendar do |date| %>
<%= date %>
<% end %>
「それにしても、こういうのを効率よく書こうとすると現実にはたいていうまくいかないですよね🤣:カレンダーを全部ループで書くのはよくないかなってつい思っちゃうじゃないですか: 3重ループの中で同じメソッドを何回も呼ぶぐらいならプリレンダリングしようなんて思ってやると、後でハマるハマる🤣」「🤣」「なまじ効率よく書いちゃうと、月表示の他に週表示もやりたいとか、週始まりを月曜から日曜に変えたいみたいな要件が来たときにつぶしが利かなくなる🔨」
「他にもBootstrapの縦分割が12だから、カレンダーを7日表示や5日表示にするときにつらいって言ってました」「それBootstrap 4ならできますよ: Bootstrap 3だとできないけどネ」「Bootstrap 3はFlexbox↓が使えないから🤣」「そういえばIE9縛りがあるとFlexboxが使えないからBootstrap 4が使えないんですよね😭」
See the Pen Demo Flexbox 1 by Hugo Giraudel (@HugoGiraudel) on CodePen.
「Bootstrap 4だとどうやるんでしたっけ🤔」「こんなふうに数値を付けないcol-*
↓を使えばFlexboxで均等割になってくれますね😋」「おほー😃」「カレンダーの7分割もこれでイケます💪」
<!-- getbootstrap.comより -->
<div class="container">
<div class="row">
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
<div class="col-sm">
One of three columns
</div>
</div>
</div>
参考: Rails で簡単にカレンダーを扱える simple_calendar で週表示カレンダーのフォーム作成を試す - Qiita
⚓スコープよりクラスメソッドの方がよい場合
2015年の記事ですが。
# 同記事より
# app/models/review.rb にスコープで書いた場合
scope :created_since, ->(time) { where("reviews.created_at > ?", time) if time.present? }
# クラスメソッドで書いた場合
def self.created_since(time)
if time.present?
where("reviews.created_at > ?", time)
else
all
end
end
つっつきボイス:「どのスコープの話かなと思ったらActiveRecordね: スコープかクラスメソッドかというのはよく言われる話で、たとえばこんな別記事もあるし↓」「これも2013年の記事だけど詳しそうですね」
参考: Active Record scopes vs class methods « Plataformatec Blog
「スコープにするならchainableでextensibleなものにすべきとあるし、かのRailsガイド様でも引数を付けるときにはクラスメソッドが推奨となってる↓」「ホントだ😳」「スコープに引数を付けるのはおすすめされてないっぽい: 実際複雑になるし」
Using a class method is the preferred way to accept arguments for scopes.
Active Record Query Interface — Ruby on Rails Guidesより
「自分はめっちゃ長くならない限り引数もあんまり気にしないでスコープで書いちゃいますけどね」「結局長くなってきたときが問題」「ただ、少なくともチェインの順序を変えると結果が変わるものはスコープにしない方がいい」「確かに」「『always chainable』っていうのはそういうことだと思う: たとえばWHEREしか使ってなければ大丈夫だけど、GROUPとかが使われているとおかしな結果になったり」「うんうん」「あとORDERが使われているスコープも、条件が複雑になったときにカオスになりやすいし」「それからスコープとクラスメソッドがどちらも使われている場合に、どういうのをどっちでやるかという方針はあったほうがいいですね🧐」
⚓Google CalendarとRailsの連携
- 元記事: Ruby Quickstart | Calendar API | Google Developers
- 元記事: HOWTO integrate Google Calendar with Rails · ReadySteadyCode
- 元記事: ruby - Connecting to Google Calendar's API through Rails - Stack Overflow
# developers.google.comより
def authorize
client_id = Google::Auth::ClientId.from_file(CREDENTIALS_PATH)
token_store = Google::Auth::Stores::FileTokenStore.new(file: TOKEN_PATH)
authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, token_store)
user_id = 'default'
credentials = authorizer.get_credentials(user_id)
if credentials.nil?
url = authorizer.get_authorization_url(base_url: OOB_URI)
puts 'Open the following URL in the browser and enter the ' \
"resulting code after authorization:\n" + url
code = gets
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI
)
end
credentials
end
つっつきボイス:「これもカレンダー絡みで: だいたいGoogle公式に揃ってるみたいですね」「GoogleのAPIにはたいていRubyのインターフェイスもあるので、Spreadsheetとかも含めてこういうのはたいていできます、ただし」「お?」「Googleに限りませんが、APIで一番よくハマるのは上限値の制約に引っかかったとき⛔」「あー😲」「たとえば1回のリクエストで取れる件数に上限があったりとかですね」
「カレンダーなんか場合、データを1リクエストでガバっと取ってきてから処理するなら全然楽勝なんですが、ちゃんとやるなら100件単位とかでループで回してデータを取ってきたりしないといけない: それ自体はそんなに大変でもないんですけど、それが面倒でガバっと取ってやろうとするとこういう制約に引っかかったりすると」「はー😞」「そういえばAWS S3にもそういう上限ありますね: 1000件ぐらいだったかな?」「まあ外部APIを使おうとするとだいたいこういう制約がありますし」
「ループもeach
でさくっと書けそうに見えたりしますが、この手の外部APIはループをeach
で単純に回してデータを取ると失敗することがあります」「お?😳」「たとえばカレンダーなら、ある瞬間のorder by updated_at的なデータを取ってきてから次のデータをリクエストする間にデータが変更される可能性があるので、そのままだと一意の結果が保証されないんですね」「おぉー😲」「正しくやるためには、そのデータを取るときにその時点のスナップショットを表すクエリIDも返してもらって、そのクエリIDと一緒にページングやorderingを扱わないといけない」「そうそう😤」「でないとorder by IDでループを回している間にデータが挿入されて、レコードが重複してコケるとかね」
「GoogleのはクエリID取れるんでしょうか?」「どっちだったかな...🤔?」「S3だと上限に達したときにnextなんとかを返してくれた覚えが」「あ、Googleにもそういうnextなんちゃらがあったと思う: でもどれでやるにしてもこの処理は面倒😢」「面倒ですよねー😞」「上限に達するぐらいデータを入れておかないとその部分をデバッグできないし💦」
⚓DataTablesをRailsで使う
- サイト: DataTables | Table plug-in for jQuery
- 元記事: Ruby on Rails and DataTables plug-in. Research of Syndicode development
- リポジトリ: DataTables/DataTables
つっつきボイス:「jQuery向けということで同じようなのは既にいっぱいありますが、割と頑張ってるかなと思って」「この時代にjQueryで攻める勇者」「でもこのぐらいのテーブルならjQueryで十分じゃね?と思う: ↓こういう動作もfunctionを書けばちゃんと実装できるし、自分はこういうのキライじゃない❤️」
⚓Railsパフォーマンス最適化手法まとめ
つっつきボイス:「割と基本というか常識的な話かな?」「プロバイダ選び、N+1、gem選び、バックグラウンドジョブ、CDN、インデックス...」「これほとんどRailsと関係ないし😆」「Webアプリ全般の最適化話やん🤣」「タイトル変えなきゃ🤓」「その分一般的に通用しそう」「はじめてWebアプリを作るのがRailsの人なら読んでおきたいヤツですね」
⚓Deviseのcustom mailerが動かなかった話
# 同Wikiより
class MyMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'devise/mailer' # to make sure that your mailer uses the devise views
end
つっつきボイス:「DeviseのWikiに書いてある通りやったのにcustom mailerが動かなくてハマった人が今ちょうどここにいらっしゃるので😇」「ああ例のw」「😤😤」「お、issue立ってるのか↓: でもcloseしてるけど?」「needs debuggingとかつぶやきながら閉じられてるんですよ😭修正されてないのに」「ひどいw」「そっ閉じw」
参考: #4842 Unable to use custom views for emails
「問題だったのは以下のdefault template_path: 'devise_mailers'
のところなんですけど」
# 同issueより
class DeviseMailer < Devise::Mailer
prepend_view_path Rails.root.join('app', 'ui')
include Devise::Controllers::UrlHelpers
layout 'devise_mailer' # is in app/ui/layouts/devise_mailer.html.haml
default template_path: 'devise_mailers' # is in app/ui/devise_mailers/...
end
「(怒涛のトーク)...まとめると、上で記述したdefault template_path:
が効いてなくて、app/views/devise_mailers
を参照して欲しいのにapp/views/devise/mailer
が参照されてしまうんですね」
# これは動く => app/views/mailer_templateを参照する
class MyMailer < ApplicationMailer
default template_path: 'mailer_template'
end
# これだと期待どおりに動かない => 相変わらず app/views/devise/mailerをみる
class MyMailer < Devise::Mailer
default template_path: 'mailer_template'
end
「あーもしかしてDeviseMailer
がActionMailerを継承しているから?」「かなっとも思ったんですが、Deviseのヘルパーにあるheaders_for
というメソッド↓がtemplate_path
を書き換えていて、それによってこちらが書いたtemplate_path
が上書きされたので、メール文言がDeviseのデフォルト文言になってしまった😇」「はは~ん、わかりみ〜☺️」
# DeviseのHelperより
def headers_for(action, opts)
headers = {
subject: subject_for(action),
to: resource.email,
from: mailer_sender(devise_mapping),
reply_to: mailer_reply_to(devise_mapping),
template_path: template_paths,
template_name: action
}.merge(opts)
「一応回避方法もissueに載ってます↓: この#headers_for
メソッドがDeviseの汎用ヘルパー的なものらしいんですけど、それをこうやってオーバーライドしろってことでした」「privateメソッド臭ぷんぷん」「でもどんな影響が生じるか読みきれないんでneeds debuggingって言ってます」「DeviseのWikiは相当読み込んだけど、この手の『privateメソッドをオーバーライドせよ』的な驚きの拡張方法をちょくちょく強いられるんですよね」「『これ本当にオーバーライドしていいの?!』みたいなのが続出するし」「『え?、configじゃなくてメソッドをオーバーライド?!』とか」「オーバーライドするしかないとかキツイわ〜」「Deviseはこういうところがキラワれがち」
# 同issueより
class DeviseMailer < Devise::Mailer
prepend_view_path Rails.root.join('app', 'ui')
include Devise::Controllers::UrlHelpers
layout 'devise_mailer' # is in app/ui/layouts/devise_mailer.html.haml
# this below has no effect
default template_path: 'devise_mailers' # is in app/ui/devise_mailers/...
# this below enables effectively the custom views path
def headers_for(action, opts)
super.merge!(template_path: 'devise_mailers')
end
end
「こういうことが起きるから、機能を拡張するときは『継承よりコンポジションしろ』って口を酸っぱくして言われるんですよね😆」「うんうん」
「今回特にムカつくのは、Wikiのコードが間違ってるのに動いちゃうところ: devise_mailer
って間違ってるけど実在するから💦」「いっそ止まってくれればよかったのに😞」
「DeviseでたとえばRegistrationコントローラを自前で作るときとか、DeviseのRegistrationコントローラをコピペするところから始めるなんてのもざらにやりますしね🤪」「そしてそのコピペをRubocopに怒られるところまでがテンプレww👮」「😭😭」「ところがところが、必要なメソッドだけ上書きするよりも全部コピペする方がまだ安全なんですねこれが」「そうかもしれない」「日暮れて道遠し感」「まさにイッツ・ア・Deviseワールド」
⚓PHPからRubyへの移行ガイド
かなりがっつりと書かれています。「Railsの方が稼げる」というセリフも。
つっつきボイス:「自分もPHPからRailsにやってきた人だったしそういえば」「Rubyなら===
とか使わなくても比較できるよみたいな?😆」
⚓外部キーなしのActiveRecord関連付け
# 同記事より
class Order < ApplicationRecord
has_one :custom_logo,
->(order) {
unscope(:where).where(
origin_value: order.origin,
client_id: order.client_id)
}
end
つっつきボイス:「↑そうそう、lambda使えば外部キーなしでもできますね」「実用的ではないんでしょうか?」「一応使えるといえば使えそう: unscope(:where)
とかやっていいのかなー?と思わなくもないけど🤔」
そういえば以前著者のTom Copelandさんの記事を翻訳しました↓。
⚓Railsで構築されたサイト40選: 2018年度版(RubyFlowより)
つっつきボイス:「よくあるリストといえばそれまでですけど」「あ、でもこういうリストは『Railsってどの辺がいいの?』って聞かれたときなんかに便利ですよ😋」「AirbnbとかShopifyとか有名どころもあるし」「DribbleもRailsか」「何のサイトでしたっけ」「デザイナー向けSNSみたいな感じでそこそこ有名」
「SlideShareやHuluもRailsとは😲」「Huluは有料動画サイトでしたっけ」「kickstarterがRailsというのは何となくわかる」「意外にいろいろあるなー🎂」
「Urban Dictionaryは翻訳で愛用してます💚」
「Basecampが16番目とは😆」「DHHのお膝元なのに」
「カスタマーサポートサービスのZendeskも!へー😲」
「BloombergがRailsなのは有名」「知らなかったー」「確かgemも出してたはず(GitHub)」
「Indiegogoもか」「これは?」「有名なクラウドファンディングサイト」
元記事のIndiegogoのリンクはなぜか間違ってました。
「えTwitchもRails?!😲」「何すかこれ?」「BPS社内Slackの格ゲー板では欠かせないヤツ💪」「最大のゲーム配信プラットフォームっす🎮」
↓開くといきなり動画が再生されます。
「CodeacademyがRailsというのも何かわかる」
「知らないサイトもあるけど、意外なサイトがRails使ってるんだなー☺️」「こういうリストのエロサイト版があったら面白いかも🤪」「?」「エロサイトってそこらのメジャーなサイトとか目じゃないぐらい普段からものすごい量のアクセスをさばいているし、いろんな意味で(笑)常に最先端を行ってるから内部にはものすごいノウハウが蓄積されてるはずなんですよね: しかもたいてい門外不出という🤣」
⚓Railsガイド日本語版に「Active Record と PostgreSQL」が追加
#Railsガイド から「Active Record と PostgreSQL」を公開しました! 🚀✨https://t.co/twH0WEgKGn
PostgreSQL に特化した Active Record 利用法を紹介&説明したガイドとなっています。
原著を眺めていると今後もどんどん加筆修正されていきそうなガイドですね ✨📜👀 pic.twitter.com/mBnBbSe2Nb
— YassLab 株式会社 🏝 (@YassLab) August 20, 2018
今日の昼に公開されました。本家英語版にもまだないエントリなので、当然ながらWIP状態です。
⚓Ruby trunkより
⚓2003年のRubyConferenceでのMatzのスライド
いつもとちょっと毛色が違いますが、Matzにっきで見かけた古きを訪ねてみました。
つっつきボイス:「2003年です」「Ruby 1.9が始まろうとしてた頃かー😲当時学生だったし」「たとえば以下のようなローカル変数スコープの変更が提案されてました↓」
# 同スライドより加工
# Ruby 1.9でのローカル変数の扱いの変更の構想
def foo
a = nil
ary.each do |b|
# bはブロックに対してローカル
c = b
a = b
# aとcはメソッドに対してローカル
end
# aとcはブロックの外でアクセスできる
puts a
puts c
end
2.5.1で試すと
NameError (undefined local variable or method
c' for main:Object)`になりました
「この頃からRubyConferenceってあったんだなー: 明らかにBefore Rails時代だし🏛」「今やお馴染みのキーワード引数やハッシュリテラル↓も提案されているし」「マルチアサインとか」
def foo(a, b: 42, **keys)
p [a, b, keys]
end
foo(2, b: 1) #=> [2, 1, {}]
foo(2, b: 5) #=> [2, 5, {}]
foo(3, b: 4, c: 6) #=> [3, 4, {:c=>6}]
# 1.8まで
{ :a => 45, :b => 55, :c => 65 }
# 1.9向け提案
{ a: 45, b: 55, c: 65 }
「このメソッド結合(method combination)って何だろうと思って」「これは明らかに今のRubyにはない」「ボツになったんでしょうね」「スゴイ書き方😅」「フックをかける書式のようだ🤔」
class Foo
def foo:pre(*args)
p "pre"
end
def foo:post(*args)
p "post"
end
def foo:wrap(*args)
p "wrap pre"
super
p "wrap post"
end
def foo(*args)
p "foo"
end
end
Foo.new.foo
# wrap pre
# pre
# foo
# post
# wrap post
個人的にはインスタンス変数にprivateスコープを作る提案↓が気になりました。本当はデフォルトでprivateにしたかったようですが、日記の方で「評判よくなかった」とあり、いずれも採用されなかったようです。
@foo = 42 # サブクラスからアクセスできる
@_foo = 55 # そのクラス/モジュールからのみアクセス
⚓提案: 名前空間の改善
# 同issueより
class Foo
end
# Kernel#namespaceの導入
namespace :Hello do
# 名前空間のカオスを回避
# Foo -> NameError, can't access TOPLEVEL_BINDING directly
# Kernel#importはFooという名前をOPLEVEL_BINDINGから導入する
import :Foo
# 名前空間内では、インポートした名前にしかアクセスできない
Foo
# 定数は別のエイリアス名にインポート
# ネストしたモジュール名/クラス名を書くことを回避できる
import :"A::B::C::D", as: :E
# requireしてインポートするショートハンド
import :"A::B::C::D", as: :E, from: 'some_rb_file'
# 2つのgemから同じ名前をインポート
import :"Foo", as: :Foo_A, from: 'foo_a'
import :"Foo", as: :Foo_B, from: 'foo_b'
# 名前をバッチでインポート
import %i{"A::B::C::D", "AnotherClass"}, from: 'some_rb_file'
# インポートとエイリアス化をバッチで
import {:"A::B::C::D" => :E, :Foo => Foo2}, from: 'some_rb_file'
class Bar
def xxx
# 名前空間のスコープ内にあるすべての名前にアクセスできる
[Foo, Foo_A, Foo_B]
end
end
end
その後
namespace
をisolate
に変えて提案しています。
つっつきボイス:「Rubyに名前空間とは」「お、確かRailsにそれっぽいものがいくつかあったと思う: Rubyの機能じゃないんですよね」「そうそう」「Railsじゃない普通のRubyコードでnamespace
って書いたらundefinedって言われた覚えはある」「(RubyMineで探す)お、たとえばこれですね↓(GitHub)」「おー」
# rails/railties/lib/rails/command/base.rb
# Convenience method to get the namespace from the class name. It's the
# same as Thor default except that the Command at the end of the class
# is removed.
def namespace(name = nil)
if name
super
else
@namespace ||= super.chomp("_command").sub(/:command:/, ":")
end
end
※ルーティングにもnamespaceがありますね。
「Rubyだとモジュールでも名前空間を切ることはできるけど、明示的に名前空間を切るという意味ではnamespace
っていうキーワードはRubyにもあっていいんじゃないかなとは思いますね」「むしろRubyにデフォルトでnamespace
がないのが少々驚き😮」
⚓RubyソースのインデントはTabから8スペースに
#14984を追ってて見つけました。
RubyのCファイル238個を調べたところ
* スペースインデントのみ: 10件
* タブインデントのみ: 66件
* インデントなし(!): 61件つまり残り101ファイルはタブ/スペースインデントが混じっているということ。
同issueより大意
つっつきボイス:「少し前にUrabeさんが提案してました」「なるほど☺️これは揃えないとねー」「↑ちゃんと調べてるしスゴイなー😲」「Cのソースレベルだと他にもいろいろ揃ってないものがありまくりそうだけど、せめてインデントだけでもってことなんでしょうね」
⚓Ruby
⚓ngx_mruby: Nginxにmrubyを
- リポジトリ: matsumotory/ngx_mruby
RubyKaigi 2018でも話されていました
参考: ngx_mruby v2のHTTPクライアントをv1よりも最大90倍高速にした - 人間とウェブの未来
参考: Rubyエンジニアはsleep 1で殺せる、をngx_mrubyのAsync.sleepで乗り越える - The paradigm shift
つっつきボイス:「『sleep 1
で殺せる』記事で見かけたので」「そうそう、sleep 1
はマジで死にますよ: コントローラとかに絶対書いちゃダメなやつ」「ギャー!それはダメー!😩」「やったらどうなるんでしょう?」「ワーカーが詰まるw」
「Rubyでなくたってsleepはあかんでしょう...😅」「でもまあ、慣れてないとAPIアクセスなんかで間を空けたいときについsleepを入れたくなっちゃうんでしょうねー: そんなにやりたかったら非同期でやれと😆」
「そういえばブラウザのJavaScriptでsleep使いたくて探し回ったことありました」「setTimeout()
」「ブラウザのJavaScriptでsleepする分には何の問題もないんですけど、サーバーサイドのRubyコードでsleep
するとその間ワーカーをがっちり掴んで離さない: とっても簡単に死ねる😇」「😆」
参考: JavaScriptでループ中にスリープしたい。それも読みやすいコードで - Qiita
⚓DIとハードコード定数のいいとこ取り(RubyFlowより)
class RegisterUser
attr_reader :validator, :repo
def self.build
new(
validator: UserValidator.new,
repo: UserRepository.new,
)
end
def initialize(validator:, repo:)
@validator = validator
@repo = repo
end
def call(params)
if validator.validate(params)
repo.save(params)
else
nil
end
end
end
つっつきボイス:「DIするとスタブやモックを入れやすいよ、みたいな話なんでしょうね: test doubleとか」「で上のアプローチ↑では、実装はDIだけど、validator: UserValidator.new
のようにハードコードするってことか」「おー、これはキレイキレイ❤️」「この書き方は割とよく使いますね: 書いた時点では1種類しかないからこういう形にしておくけど、後でほぼ確実に増えることが予測できる場合なんかに拡張性を担保できるのがいいですよね😋」「ま、オーバーキルにも見えるので普通にハードコードしちゃうこともありますが😆」
「あたしもinitialize
のデフォルト引数でこうするのが最近お気に入り😍」「それも同じコンセプトですね: 実装をDIにできるし、引数もキーワード引数にしておけばなおいいし」
⚓dry-rbでサービスを設計する(Awesome Rubyより)
# 同記事より
class NotifySlack
extend Dry::Initializer
option :message
option :notifier, default: -> { Slack::Notifier.new(URL) }
def self.call(**args)
new(**args).call
end
def call
notifier.ping(message)
end
end
つっつきボイス:「ここでも依存性の注入が登場していました」「そういえばDependency Injectionを『依存性の注入』と言うのってどうかな~と思ったり😉」「あーそういえばそうだったか💦」
「まあ多くの日本語書籍で『依存性の注入』と訳されちゃっている現実があるんですが、この記事がひと頃流行りましたよね↓」「これ見たことあったそういえば👁」「それもあって自分はDIと言うようにしてる😎」
「注入って言葉が何かよくないっすよね」「そうそう、注入というよりイメージとしては差し込む感じ」「ジェネリクスというか」「しかも注入するものって依存性じゃないんですよね」「そうそう🤣」「どっちかというと『差し替え可能にすることで依存しないようにする』なんじゃ?」「dependencyとinjectionをそのまま訳しちゃったからこういうことになったんでしょうね〜」「元の英語もそれなりに残念な気がしますね」「たぶんinjectionを『注入』としちゃったのが敗因じゃないかな〜?」「dependencyも何か問題ありそう」「もう慣れちゃったから依存性の注入でもいいかなっと😉」「日本語にしないのが確実かも」「実際に日本語で言う人見たことないなー」「本で覚えちゃった人は言うかもしれない」「読むときも心の中でDIに差し替えてるし🧐」
確かに「依存性」も「注入」も薬物依存を強く連想してしまいがちですね。プログラミング言語の仕様を後からドラスティックに変えるのが困難なように、翻訳もいったん定着してしまった用語を覆すのは大変です。自分ひとりではできない作業なので💦。
そういえば「差し込み印刷」がmerge printの訳語だったのを思い出しました。これはいい訳だと思います💪。
参考: 差し込み印刷とは - IT用語辞典 Weblio辞書
⚓次に学ぶ言語にRubyを選ぶことの知られざるメリット(RubyFlowより)
つっつきボイス:「『Rubyistはフレンドリー』😆」「😆」「『Rubyistは美しいコードを心がける』ホントかー?🤣美しいとは言い難いコードも山ほど見たけどなっ」「🤣」「オープンソースのコードを書いている人ならRubyに限らずだいたいそうだと思う」「他のコミュニティ向けの記事みたいです」「確かにRubyコミュニティは不毛な論争になりにくい感じはありますね😋」
⚓Ruby関連カンファレンス情報
大江戸Ruby会議に値段が2種類あるのが謎でした。
つっつきボイス:「5,656円ってもしやゴロゴロ😆」「語呂合わせ」「雷門にかけてるのか」「倍以上違うし🤣」「前回は御茶ノ水で今回はお膝元の浅草ですが、自分は御茶ノ水の方が行きやすいなーと思ったり」「花やしきの裏か」
こちらも↓。
Are you:
✅Coming to @rubyconf?Have you:
✅Been to a Ruby conference before?Do you:
✅Want to be AWESOME???Then you'd make a great guide for a scholarship recipient! 😄
Help someone get the most out of their first Ruby conference. Apply by Aug 30: https://t.co/yBHs5ivO2b
— Sarah Mei (@sarahmei) August 14, 2018
⚓JSONを安全に「mung」する(RubyFlowより)
- 元記事: Safer JSON munging ·
# 同記事より
def munge(hash)
instructions.each do |inst|
inst.call(hash)
end
hash
end
つっつきボイス:「このmungって言葉が割と謎で」「mail munglingとかじゃなくて?」「mungleじゃなくてmungeなんですがさっき手元の串刺し辞書検索で見つからなくて💦」「(しばらく探す)お、Macの英英辞典にあった↓🎯」「へー!」「しかも例文がIT系でピンポイントの内容」「『操作する』」「mungまたはmungeなのね」「しかもmash until no goodの略語という説が: すげー😳」「時間ないので次へー」
⚓Ransack gemのyaml翻訳を増やしたい(RubyFlowより)
つっつきボイス:「珍しくRubyFlowのエントリをそのまま貼ってみました: Ransackのローカライズ済みyamlをもっと増やしたいんだそうです」「『みんな!オラにyamlをくれ!』みたいな😆」「日本語yamlは3年前のがもうあるのね」「今のところyamlは18言語分、と」
- リポジトリ: activerecord-hackery/ransack
⚓クラウド/コンテナ/インフラ/Linux/Serverless
⚓Aurora Serverless MySQLがリリース
- 元記事: Aurora Serverless MySQL の一般利用が開始 | Amazon Web Services ブログ
- サイト: Amazon Aurora – 自動スケーリングサーバーレスデータベースサービス – AWS
つっつきボイス:「AuroraのこのサービスをServerlessって呼んでいいものかどうか微妙〜😆」「😆」「どんなサービスでしたっけ」「単にMySQL connectしたタイミングでRDSインスタンスが起動するヤツです」「?」「つまりインスタンスは普段は止まっていて、MySQL Connectすると勝手に起動してくれて、接続が終わったらしばらくしてまた自動的に止まるということ」
「よくバッチ処理なんかで一時的に激しくアクセスしたいなんてときに、これまでだとRDSの起動や終了を手動でやらないといけなかったんですが、そういうのをお任せでやってくれるというイメージ」「ほほ〜」「だからこのサービスはバッチ処理に向いてると思うんですよね」「確かに使いみちはありそうっすね: しかしServerlessかと言うとw」「Aurora On-Demandとかそういう名前の方がよくね?」「流行り言葉だからServerlessって言ってみるテスト?」「インスタンスを起動するのに1分とかかかるから、即時性を要求するものよりは、やっぱりバッチ処理に向いてるんじゃないかなー🤔」
「Lambdaと相性がいいとかあるんですかね?」「いや特に😆」「Lambdaも即時応答を必要としないバッチ的なものならいけるでしょうし☺️」
「そういえばAWS Batchってのもありますね?」「あれはただのバッチで🤣、cron的にEC2インスタンスを起動してコマンドを実行して終わったらインスタンスを落とすとかに使う」「なんだ🤣」
⚓Cookieの次はSec-HTTP-Stateヘッダ
Sec-HTTP-State: token=J6BRKagRIECKdpbDLxtlNzmjKo8MXTjyMomIwMFMonM
Googleの中の人です。
draft-cdn-loop-prevention-00 - CDN Loop Preventionというのもありました。
参考: Cookieにかわる Sec-HTTP-State ヘッダの提案 - ASnoKaze blog
つっつきボイス:「これはてブで見ましたネ」「先週出した勉強会記事↓の最後のステートレスとステートフルの話にも書きましたけど、CookieってステートレスなHTTPプロトコルの上でステートフルな振る舞いを実現するために使われまくっているわけで、WebアプリがCookie使ってステートフルなのはもう当たり前になってしまってますよね」「ですねー」「それほどまでに使われているのに、Cookieって未だに不便なところが多すぎ😭」「記事にあるけど『secure属性やhttp-only属性の利用率は10%に達してない』のが悲しすぎる😢」「かーなーしぃー😞」
「ブラウザを替えると動かなくなるアプリだって多すぎるんだし、それなら新しいものを定義した方がいいっていう発想は自然」「↓こういうの見るとCookieも限界だなって思いますね」
Cookie request header is 409 bytes, while the 90th percentile is 1,589 bytes, the 95th 2,549 bytes, and the 99th 4,601 bytes
同記事より
「問題なのはCookieの仕様がレガシーすぎることで、ブラウザのCookie APIを生で触るとかホント地獄ですよ💀やったことあります?」「ありますw」「あそこにはいわゆるPOST
パラメータがそのまんま入ってるんで、JSON的にオブジェクトをCookieに格納しようと思ったら自分でシリアライズしないといけないという🤮」「一応js-cookie↓というのを使うとキーに保存できますけどね」「つかそもそもCookieだけではキーにセットすることすらできないんだからぁああ😤」「CSSですらやれることもできないCookieって...😅」
- リポジトリ: js-cookie/js-cookie
「その点SessionStorageとかlocalStorageはキーバリューストアとして使えることが保証されているんで、断然使いやすいですね😍」「GoogleスプレッドシートのデータとかはlocalStorageに保存されてるんでしょうね...」「バカでかいJSONデータみたいなものはよくlocalStorageにそのまんま放り込まれてたりしますね🗻」「indexedDBなんかは確かSQLライクにちゃんと扱えるんですよね?」「そうそう😋あんまり実装されてないけど」
参考: HTML5 SessionStorageの使い方 - WebStorageを使ってみよう!
参考: Window.localStorage - Web API インターフェイス | MDN
⚓REST APIはデータベースではない(Awesome Rubyより)
つっつきボイス:「RESTはー、データベースじゃー、ないよー😆」「😆」「この絵好き↑」
⚓go-health: ヘルスチェッカー
- リポジトリ: InVisionApp/go-health
つっつきボイス:「このGopherくんみたいな絵ってみんなどこから仕入れてるんだろか?😆」「😆」「眼球よく見たら完全な球体w」「ヘルスチェックっていかに軽くするかが至上命題ですね🧐」
ついでにこんなのを見つけちゃいました。
- リポジトリ: StickmanVentures/go-gopher-model -- Gopherくんの3Dデータ
⚓モバイル/Android/iOS
⚓Lottie: Adobe After Effectsアニメーションを直接動かせるライブラリ
つっつきボイス:「BPSアプリチームとデザインチームがこれにちょっとざわついてました」「After Effectsを直接かけられるとはねー😲よく頑張ったなってマジで思う」
参考: Adobe Creative Cloud | プロのクリエイター向けソフトウェアとサービス
⚓Flipper: Facebookのモバイルアプリデバッガ(JSer.infoより)
つっつきボイス:「うん、こういうのはいろいろあるけどやっぱり便利😋」「SafariのDeveloper Toolsとかでもある程度できるけど時々扱えない項目とかあったりしますね」
⚓SQL
⚓JOINのコスト(Postgres Weeklyより)
- 元記事: Cost of a Join
-- 同記事より
EXPLAIN ANALYZE
SELECT
count(*)
FROM
table_1 AS t1 INNER JOIN
table_2 AS t2 ON
t1.id = t2.table_1_id INNER JOIN
table_3 AS t3 ON
t2.id = t3.table_2_id INNER JOIN
table_4 AS t4 ON
t3.id = t4.table_3_id INNER JOIN
table_5 AS t5 ON
t4.id = t5.table_4_id
WHERE
t1.id <= 10;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=88.52..88.53 rows=1 width=8) (actual time=0.411..0.411 rows=1 loops=1)
-> Nested Loop (cost=1.43..88.50 rows=9 width=0) (actual time=0.067..0.399 rows=10 loops=1)
-> Nested Loop (cost=1.14..85.42 rows=9 width=4) (actual time=0.054..0.304 rows=10 loops=1)
-> Nested Loop (cost=0.86..82.34 rows=9 width=4) (actual time=0.043..0.214 rows=10 loops=1)
-> Nested Loop (cost=0.57..79.25 rows=9 width=4) (actual time=0.032..0.113 rows=10 loops=1)
-> Index Only Scan using table_1_pkey on table_1 t1 (cost=0.29..8.44 rows=9 width=4) (actual time=0.015..0.023 rows=10 loops=1)
Index Cond: (id <= 10)
Heap Fetches: 10
-> Index Scan using table_2_table_1_id_idx on table_2 t2 (cost=0.29..7.86 rows=1 width=8) (actual time=0.007..0.007 rows=1 loops=10)
Index Cond: (table_1_id = t1.id)
-> Index Scan using table_3_table_2_id_idx on table_3 t3 (cost=0.29..0.33 rows=1 width=8) (actual time=0.008..0.008 rows=1 loops=10)
Index Cond: (table_2_id = t2.id)
-> Index Scan using table_4_table_3_id_idx on table_4 t4 (cost=0.29..0.33 rows=1 width=8) (actual time=0.007..0.008 rows=1 loops=10)
Index Cond: (table_3_id = t3.id)
-> Index Only Scan using table_5_table_4_id_idx on table_5 t5 (cost=0.29..0.33 rows=1 width=4) (actual time=0.007..0.008 rows=1 loops=10)
Index Cond: (table_4_id = t4.id)
Heap Fetches: 10
Planning time: 2.287 ms
Execution time: 0.546 ms
(19 rows)
しょっぱなで「場合によりけり」とあります。
つっつきボイス:「おータイトルがかっこいいなー😎」「↑ぽすぐれはこうやってクエリプランがとっても読みやすいのがホントいい❤️」「MySQLのクエリプランは、読めるけど読めないw」「フォーマットしてハイライトしてもあかん感じでしょうか?」「MySQLのはテーブルで出力されるますしねー💦」「クエリがどういう戦略で組み立てられたのかが結局よくわかんない😭だからforce indexしたりwhereの順序を変えたりとかして試さないと」「最後はログからMySQL様のお気持ちを読み取ることに🤣」「そうそう🤣」
「ポスグレの出力はどこを評価したらどうなったかというのが逐一分かるのがエライ」「しかも数値付きだし」
⚓時間のかかるクエリ
この比較的シンプル(に見える)SQLが380時間とかかかるの何なの? という話https://t.co/9C7e7tYYMX
— 7594591200220899443 (@shyouhei) August 7, 2018
つっつきボイス:「これMySQLだし」「およ、Using temporary
してるし↓これはヤバいやつ」「というと?」「これをやると中間テーブルを一度ファイルに出すんですけど、そうすると何やかんやでディスクがボトルネックになっていく」「あぁ〜😲」「それがサブクエリになってたりするともうあかん🤣」「🤣」
+------+-------------+-----------------+--------+---------------+---------+
| id | select_type | table | type | possible_keys | key |
+------+-------------+-----------------+--------+---------------+---------+
| 1 | SIMPLE | project_commits | ALL | NULL | NULL |
| 1 | SIMPLE | commits | eq_ref | PRIMARY | PRIMARY |
+------+-------------+-----------------+--------+---------------+---------+
+---------+-------------------------------------+------------+-----------------+
| key_len | ref | rows | Extra |
+---------+-------------------------------------+------------+-----------------+
| NULL | NULL | 5417294109 | Using temporary |
| 4 | ghtorrent.project_commits.commit_id | 1 | |
+---------+-------------------------------------+------------+-----------------+
追いかけボイス: もう少し具体的にはこんな流れ:
- JOINやサブクエリで必要な一時テーブルのサイズが
tmp_table_size
とかmax_heap_table_size
(今は名前違うかも?)とかから算出されるサイズを超えるとtemporary tableとしてファイルに書き出し始める - ↑の時点で既に激遅いのに、さらにファイル書き出し&READが発生するため、OS側で空きメモリを使って実施しているファイルキャッシュがゴリゴリ破棄されていく
- 他のプロセスのキャッシュもガンガンページアウトされ、次回参照時にまたディスクから読みに行く
- 実質メモリ足りない時のスラッシングに近い状況が発生する
「『5 billion rows and commits 847 million rows』というボリュームでやってたらそうなりそう: よく10日も待ってたって思う😢」「クエリがなかなか戻ってこない時の判断って迷うよね: productionでどれぐらい時間かかるクエリを回したことあります?」「productionじゃないけど、移行の時にproduction相当のセッティングにして3時間経っても戻ってこないからこれは絶対何かおかしいと思って、速攻アプリを閉じてOracleを再起動したら10分かからずに返ってきましたね🤣」「🤣」「チューニング無しで12時間かかるクエリをチューニングして6時間まで短縮して、それをproductionで回したことならある😆」「夜が明けるまでが勝負のヤツですね」「SQLで1000行ぐらいあったかな」「ぶほっ」「SQLのありがたいところは、途中でエラーがraiseされたりしないところですね☺️」
⚓JavaScript
⚓Vue.jsのAsyncコンポーネント
// static import
import utils from "./utils";
// dynamic import
import("./utils").then(utils => {
// utils module is available here...
});
つっつきボイス:「then
で書けるようになったってことみたい」「then
ってES2015あたりで入ってきたんだったかな?」「Promiseのthen
ですね」
参考: Promise - JavaScript | MDN
「そういえばRubyでもthen
入ってきましたね」「あーyield_self
の名前がRubyKaigiで変わったヤツ」「へー知らなかった」
⚓WebpackのHMR(Hot Module Replacement)とは
つっつきボイス:「HMRは今日の社内の勉強会の発表で出てきたので: Webpackerのつらさがよくわかるスライドでした☺️」
参考: モジュールをHMRに対応するための実装について - Qiita
⚓Electron Fiddle(JavaScript Weeklyより)
Fiddleで書いたものをElectron Forgeを使ってElectronアプリにできるようです。
- サイト: Electron Forge
⚓CSS/HTML/フロントエンド/テスト
⚓配色アイデア見本2018年保存版
つっつきボイス:「BPSデザインチームが感動してました: とってもキレイですね」「こういうのは自分で直接カラーパレットいじるとろくなことにならないという」「カラーパレットはやっぱりツールを使って選ぶべきですねー」「そういうサイトもいろいろあるし」「Photoshopにもありますし」
⚓WordPressの編集画面が5.0で変わる
WordPressの更新情報で気が付きました。
参考: Before Gutenberg - WordPress 5.0になるまでに準備すべきこと - Capital P
つっつきボイス:「どうよくなるのか次第ですけどねー」「今までのTinyMCEがあまりに歴史古いし: 相当前からある」「TinyMCEで編集中にdiv
から抜けたつもりでEnter押してたら抜けてなかったなんてことあった😢」「TinyMCEの出た頃ってtableレイアウト全盛でしたね☺️」「Gutenbergになったらどうなるのかちょっとだけ心配っす: Markdownしか使わないけど」「Markdownは大丈夫でしょうきっと」
⚓言語よろずの間
⚓lem: Common LISPベースのEmacsエディタ
- 元記事: Emacsからlemに移行した - 八発白中
- リポジトリ: cxxxr/lem
つっつきボイス:「まあエディタは好きなものを使えばいいんじゃね?☺️」「これCLIでも動きそう」「Emacsはめちゃ重いからな〜(と起動してみる)お、一回起動すると速いのかな?: 久しぶりにEmacs起動したし😆」
追いかけボイス:「どうやら以前入れていたspaceemacsが重すぎてMac更新時に捨てていたので速かったようです: 今は.emacsファイルすらないという」
⚓コンパイラは新しいフレームワークだ
「Webの人も今こそコンパイラの仕組みを学ぼう」という結論でした。
つっつきボイス:「コンパイラのことは知ってて損はないと思いますね: 『こういうコードは最適化が効きやすい』みたいのを押さえておけばスクリプトエンジンの最適化を活用できるし」
⚓日本語や中国語でルビをマークアップする(Awesome Rubyより)
- 元記事: Ruby Markup
つっつきボイス:「Rubyじゃなくてルビということで」「これ見てると例の文字渦↓を思い出しちゃう」「それそれ」「やっぱスゲー」「タイトルは中島敦の『文字禍』のもじりなんでしょうね」「このルビはまったく別の文章?」「二重化されてるっぽいですね」「他のページはもっとスゴイのかも?」
新潮社の円城塔「文字渦」を買ってきました。
おそらく編集・営業・DTP・印刷、全ての人が泡吹いて死ぬ本です。 pic.twitter.com/lA98qEyIxa— ぐれ (@guleukara) August 14, 2018
参考: 文字禍 - Wikipedia
⚓その他言語
残念だけどもうプログラミング言語作るのやめるよという話。わかる…わかるhttps://t.co/aDast9zZ7B
— 7594591200220899443 (@shyouhei) August 8, 2018
⚓その他
⚓安価なMacbook欲しい
アップル 安価なMacBookを9月以降に発売か https://t.co/wZj38A4RYn pic.twitter.com/76YgGFGjbd
— ASCII.jp編集部 (@asciijpeditors) August 14, 2018
⚓Intel CPUの「Foreshadow」脆弱性の解説ムービー
投機的実行の脆弱性、Turing Complete FMでも話されていたような覚えがあります。
つっつきボイス:「これはMeltdownとかとまた別の脆弱性?」「そうみたいです」「L1キャッシュをクリアすると安全にはなるけど遅くなっちゃうんですよね」
参考: IntelのCPUで新たに発見された脆弱性「Foreshadow」の解説ムービーをRedHatが公開中 - GIGAZINE
⚓世界最悪のログイン処理コードを鑑賞
世界最悪のログイン処理コード。
実際のサービスで可動していたものだとか……https://t.co/C2bG93ZCkj pic.twitter.com/EfVNAEslrn— はっしー@海外プログラマ🇳🇿元社畜 (@hassy_nz) August 10, 2018
つっつきボイス:「これはホントすごいよなー: 首を傾げ度がヤバい😆」「"true" === "true"
とか」「apiService.sql()
とか」「腹いてー🤣」「ツッコミどころしかない🔫」「コワイよ〜」
「C言語だったら"true" === "true"
みたいなのを書くことはたまにあるけど」「お?」「パイプラインを強制的にフォールトさせるときとか: コンパイラの最適化を全部オフにしておいてブランチ命令を実行することでパイプラインを無理やり落とすという」「ま、そういうのは普通インラインアセンブラでやるでしょうけど😆」
追いかけボイス: 「組み込み向けのマイコン開発などではこういうことが割とあります: CPU初期化系のレジスタ更新がスペックシート上はすぐに反映されそうに書いてあっても、実際には数クロック待たないと反映されないケースではNOP NOP NOP NOP
したりするなどです」
⚓その他のその他
- 元記事: Google Online Security Blog: Google Public DNS turns 8.8.8.8 years old -- Googleの
8.8.8.8
が8歳8か月に - 元記事: Draft Emoji Candidates
僕が今書いているCコンパイラ本の目的は、セキュキャンとかではなくても誰でもご家庭で自分のCコンパイラが書けるようにするということですね。できると思う。
— Rui Ueyama (@rui314) August 13, 2018
⚓番外
⚓回路で遊ぶ
⚓木星並の漂流惑星が発見される
記事の方ではこの惑星をNibiruと呼んでました。
参考: ニビル (仮説上の惑星) - Wikipedia
参考: どの星系にも属さず宇宙を漂流する巨大惑星を発見 - NRAOなど | マイナビニュース
今回は以上です。
バックナンバー(2018年度後半)
週刊Railsウォッチ(20180813)Rails 5.2.1リリース、sanitize_sql_arrayは5.2からpublicだった、Dev.toがRailsアプリのソースを公開ほか
- 20180806 Rails 5.2.1.rc1リリース、Railsガイド日本語版が5.1に対応、Regexp#match?ほか
- 20180723 Railsdm Day 3 Extremeを後追い、PSDにはZeplin.io、好みの分かれるJSX、負荷テストツール比較ほか
- 20180709 Rails Developers Meetup Day 3 Extreme今週末開催、RailsのSTI/キャッシュ/添付ファイル/Redis/PDF出力、ECMAScript 2018、プロフェッショナルIPv6ほか
- 20180702 Ruby 2.2メンテ正式終了、Ransackがつらくなるとき、書籍『Domain-Driven Rails』、GitHubの高可用MySQLほか
- 20180622 Railsの需要未だ巨大、Unicode 11.0リリース、WebDriverがW3Cで勧告、Flutter.io、2封筒問題ほか
- 20180615 TTY gemとHTTPClient gemは優秀、Rubyの謎フリップフロップ、ちょいゆるRubyスタイルガイドほか
- 20180608 特集「RubyKaigi 2018後の祭り」、
Enumerable#index_with
は優秀、コントローラから@
を消し去るほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。
従来のコードでは、例えば「最新データがキャッシュにあればキャッシュから拾い、なければDBを参照する」みたいな動作を期待している時に一度
nil
をキャッシュしてしまうと、DBに新しいデータが入ってもキャッシュがexpireするまでnil
を返してしまう仕様でした。ただ、これはキャッシュエンジンの仕様としてはあながち間違いではありません。DB側を更新する時に明示的に対応キーのキャッシュを飛ばす実装にすればそれでも正しく動くからです。
今回の変更の
:skip_nil`
オプションは、その辺のキャッシュ自動管理を多少サボれるようになります。一度作られたら変わらないデータみたいなものをキャッシュに載せる場合には手軽に使えて便利という感じです。ただし楽になるのは新規追加の時だけで、updateの場合には結局手動でキャッシュ飛ばすコードが必要です。この設定が手動で必要なことを見落とすと、古いデータが更新されないというIssueが上がってくる所までがワンセットになりそうな予感がします。