開発備忘録 2018/10/24

MySQL で SELECT の結果に対して UPDATE を適用する

statustemp のレコードを全て active にする。

UPDATE
  users,
  (
    SELECT users.id
    FROM users
    WHERE status = 0 # 0: temp, 1: active, 2: leaved
  ) AS temp_users
SET users.status = 1
WHERE users.id = temp_users.id

FactoryGirl の transient について

FactoryGirl において一時的な attribute を定義することができる。
transient で定義した attribute はモデルを build (create) した際にセットされることはなく、また attribute_for で attribute を取り出すときには無視される。

何のためにこの機能が提供されているかというと DRY に書くためである。
例えば、以下の FactoryGirl のコードを DRY にする方法について考えてみる。

factory :character do
  name { "Jack (job)" }

  trait(:knight) do
    name { "Jack (knight)" }
  end

  trait(:fighter) do
    name { "Jack (fighter)" }
  end

  trait(:wizard) do
    name { "Jack (wizard)" }
  end
end

job に応じて name の表記が微妙に変わるというものだが、今回の場合だと name { "Jack" } の部分が重複していて DRY ではない。
これが transient を使うとこう書ける。

factory :character do
  transient do
    job "job"
  end

  name { "Jack (#{job})" }

  trait(:knight) do
    job "knight"
  end

  trait(:fighter) do
    job "fighter"
  end

  trait(:wizard) do
    job "wizard"
  end
end

job を transient に定義しておいて、trait で job の値を更新するというわけだ。
ちなみに job の値を外から渡したい場合はこう書く。

create(:character, job: 'thief')

また callback で transient を利用したい場合は第二引数が transient なのでそれを利用する。

factory :character do
  ...

  after(:create) do |character, evaluator|
    character.name += " #{evaluator.job}"
  end
end