ActiveRecord で unscoped を呼ぶとその前のクエリが消える

久々ですこんにちは。
毎日ブログを書くとはなんだったのか…。
そろそろアウトプットしたいな〜〜〜と思い始めてきたのでぼちぼち書いていきたい…。

unscoped を使うことで default_scope を取り除くことができる

さて、皆さん大好き default_scope ですが、モデルで default_scope を定義すると次のように暗黙的にクエリが追加されます。

class User < ActiveRecord::Base
  default_scope { order(:updated_at) }
end

# 暗黙的に ORDER BY のクエリが追加れる
puts User.all.to_sql
# => SELECT "users".* FROM "users" ORDER BY "users"."updated_at" ASC
puts User.where(name: "Tom").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom' ORDER BY "users"."updated_at" ASC

毎回 order(:updated_at) する必要がないので便利ですね。
でも『あ〜今日は default_scope のクエリ追加してほしくないな〜〜〜』って思うときがあると思うんですよ。
そういう時に unscoped を使うと default_scope のクエリを取り除く事ができます。

# unscoped を付けると default_scope はつかなくなる
puts User.unscoped.all.to_sql
# => SELECT "users".* FROM "users"
puts User.unscoped.where(name: "Tom").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom'

これで default_scope をつかっていてもシュッと取り除く事ができて便利ですね!

default_scope 以外のクエリも取り除かれる

unscoped を使うことで default_scope を取り除く事ができるようになります。
しかし unscoped はめちゃくちゃ強くて『呼び出すよりも前のリレーション』も取り除いてしまします。

# unscoped よりも前に付けた where のクエリも消してしまう
puts User.where(name: "Tom").unscoped.to_sql
# => SELECT "users".* FROM "users"

unscopeddefault_scope を消したい場合は必ず『一番最初』に unscoped を呼び出しましょう。
逆に『レシーバのクエリを全部消したい』場合は unscoped を呼び出すと一括で消すことができるので便利です。

あなたの知ってるRubyGemsTips で LT してきた

あなたの知ってるRubyGemsTips で LT してきました。
LT よかったよー、と言ってもらえたのでよかったよかった。

printf デバッグが捗る gem をつくった話

2年ぐらい前に binding-debug という gem をつくったんですが、最近いろいろと機能拡張したのでそれの紹介をしてきました。
以前は

require "binding/debug"

using BindingDebug

value = 42
binding.p "value"
# => value : 42

みたいに binding.p に文字列を渡して使うようになっていたんですが、いまは Ruby の闇の力を使い以下のように書くことができます。
以下、README にかかれているサンプル。

require "binding/debug"

using BindingDebug

def plus a, b
  a + b
end

foo = "homu"

# puts with blocks
puts {
  foo.to_s.upcase
  plus 1, 2
  (0..20).to_a
  foo.class.name
}
# output:
# foo.to_s.upcase : HOMU
# plus 1, 2 : 3
# (0..20).to_a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# foo.class.name : String

今回は5分の LT でユースケースや使い方ぐらいしか話せなかったんですが、機会があれば実装方法なんかも話してみたいですねー。
ご飯も美味しかったですし、運営の方々ありがとうございましたー。

JavaScript で全角スペースはホワイトスペースとして扱われる

JavaScript で全角スペースを書いた場合、ホワイトスペースとして扱われます。知らなかった…。
なので次のように全角スペースが含まれているコードでも実行する事ができます。

if ( true ) {
  console.log("hoge");
}

うーん…便利…なのか?

参照

Ruby でクラス名と同名のメソッドを定義する

Ruby ではクラスと同じ名前のメソッドを定義する事ができます。

class X
end

def X(a = nil)
  "X(#{a})"
end

# 何もつけなかった場合はクラスを参照
p X       # => X
# メソッドぽい呼び出しであればメソッドを参照
p X()     # => "X()"
p X 42    # => "X(42)"

この手のやつでよく利用されているのは Kernel.#Array メソッドや Kernel.#Integer メソッドですねー。

Array(arg) もクラスではなくてメソッドを呼び出しています。

Ruby の private メソッドを特定のコンテキストで public にする

Ruby では次のように private メソッドにすると『レシーバをつけたメソッド呼び出し』ができません。

class X
  private

  def value
    42
  end
end

x = X.new

# error: private method `value' called for #<X:0x00007fabe905fa40> (NoMethodError)
x.value

こういうときに refinements を使うと任意のコンテキストでのみ public 化することができます。

class X
  private

  def value
    42
  end
end

x = X.new
# error
# x.value

# refinements を使って public 化する
using Module.new {
  refine X do
    public :value
  end
}

# OK
x.value

べんり。

Ruby で任意の定数を参照した際に警告が出るようにする

Ruby で任意の定数を参照した際に警告が出るようにしたい場合、 Module#deprecate_constant を利用することができます。

class X
  Hoge = 42
end

# no warning
X::Hoge

# X::Hoge を参照すると警告を出すようにする
X.deprecate_constant :Hoge

# warning: constant X::Hoge is deprecated
X::Hoge

こんなのが標準ライブラリにあるんですねー。 使う機会があれば使ってみたい。

Omotesando.rb #54 で『ActiveRecord のコードを読んでみる』をしてきた

Omotesando.rb #54 で LT してきました。
今回は「コードの読み方」というテーマだったせいかいつもよりもめっちゃ人が集まっていましたねー。人が多いけど懇親会でぼっちだったワイ
やっぱり「コードの読み方」っていうのは初心者から上級者まで興味があるテーマになるんですかねー。

ActiveRecord のコードを読んでみる

ActiveRecord のコードを読んでみる』ってことでスライドは使用する機能の説明だけ書いて実際にいつもどんな感じで ActiveRecord の実装を読んでいるのかのデモをしてきました。
pデバッグ出力したり grep で検索したり binding.irb を駆使したりと割と泥臭い機能を使ってコード読んでいます。
このあたり、使っているエディタによって結構違ってて RubyMine とかは高級な機能を使って便利そうにデバッグしていました。
最近 Vim の拡張はサボり気味なので Vim でもいろいろとやってみたいんですけどねえ…。
あ、あとわたしは binding.pry ではなくて binding.irb を使っているんですが『なんで binding.pry じゃないんですか』って何人かに聞かれました。
わたしも昔は binding.pry 使っていたんですが Railsbinding.pry を使うと変なところで止まっちゃうことが多くで確実に動作する binding.irb を使うようになりました。
binding.pry よりも高級ではないんですがより安定性があるから使っているって感じですねー Ruby 2.7 からは irb のかなり強化されているのでこれからに期待しています!!!