9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ActiveRecord のデフォルト値

Last updated at Posted at 2014-10-23

ActiveRecord が DB の DEFAULT で設定した値を attribute の初期値として設定してくれるという挙動を知らなかったため、軽くハマってしまったので忘れないようにメモ。

Migration を使っていない案件で DB の DEFAULT 値を ALTER 文で変更したら急にテストが失敗するようになったが、コードは特に弄っていなかったのでなかなか原因に気付けなかった。

試してみる

例えば Model に以下のようなバリデーションを設定。

class Post < ActiveRecord::Base
  has_many :comments
  validates :title, presence: true
end

この状態で rails console で Model を new して valid? を呼ぶと以下のようにバリデーションはエラーになる。

% bundle exec rails c
Loading development environment (Rails 4.1.6)
irb(main):001:0> post = Post.new
=> #<Post id: nil, title: nil, body: nil, lock_version: 0, created_at: nil, updated_at: nil>
irb(main):002:0> post.valid?
=> false
irb(main):003:0> post.errors
=> #<ActiveModel::Errors:0x007f88438d3010 @base=#<Post id: nil, title: nil, body: nil, lock_version: 0, created_at: nil, updated_at: nil>, @messages={:title=>["can't be blank"]}>

ここまでは想定通り。
ここで DB 側に以下の ALTER を流してデフォルト値を設定。

-- MySQL
ALTER TABLE `posts` MODIFY COLUMN `title` varchar(255) NOT NULL DEFAULT 'No Title';

-- SQLite
DROP TABLE "posts";
CREATE TABLE "posts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar(255) DEFAULT "No Title", "body" text, "lock_version" integer, "created_at" datetime, "updated_at" datetime);

rails console で relaod! してから再度試すと Model を new した時点で DB の DEFAULT に設定した値が入っている事が分かる。
当然 valid? の結果も今度は true になる。

irb(main):004:0> reload!
Reloading...
=> true
irb(main):005:0> post = Post.new
=> #<Post id: nil, title: "No Title", body: nil, lock_version: 0, created_at: nil, updated_at: nil>
irb(main):006:0> post.valid?
=> true

ハマった時はこの逆で、デフォルト値を数値から NULL に変えたためバリデーションエラーが発生してしまった。

恥ずかしながら今までこの挙動を知らなかったが、知っていれば便利な機能だと思う。
Migration 使ってる環境なら Model 側意識せずに DB のデフォルト値だけ変える事もそう無さそうだし。

設定している所

余りちゃんと読んでいないけど適当に grep してみると lib/active_record/model_schema.rb の 254 行目辺りで設定してるっぽい。

# Returns a hash where the keys are column names and the values are
# default values when instantiating the AR object for this table.
def column_defaults
  @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }]
end

参考

ruby on rails - How can I set default values in ActiveRecord? - Stack Overflow
http://stackoverflow.com/questions/328525/how-can-i-set-default-values-in-activerecord/328874#328874

how do set default value for ActiveRecord fields? - Ruby Forum
https://www.ruby-forum.com/topic/75429

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?