Rails5から使えるActiveRecord便利機能

RailsのChangeLogを読んでいたらkamipoさんの
ActiveRecordへのコミットがRails5から使えるようになってるものがたくさんあったのでまとめてみました。

## PostgreSQLでExpression IndexとOperator Classをサポート

```rb
create_table :users do |t|
  t.string :name
  t.index 'lower(name) varchar_pattern_ops'
end
```

## MySQLでPrepared statesmentsをサポート

`config/database.yml`で`prepared_statements: true`とすると利用できるようになります。mysql2 0.4.4以降が導入されていないと使えないようです。

## Schema dumperが`create_table`ブロックの中でindexを定義するようになった

`schema.rb`の`create_table`のブロック内で`t.index`でインデックスが定義されるように変更されています。以前は`create_table`のブロック外で`add_index`として定義されていました。この変更でMySQLは`CREATE TABLE`時に合わせてインデックスが定義され、結果として実行されるSQLが減っています。

## SQLiteで値がカラム制限を超えているときのuniqueness検証を修正

SQLite自体には列に長さの制限を設けないです（メタデータとして扱われる）。
uniquenessを検証するときに文字列を切り捨てるときに失われる値が発生する問題があります。

他のデータベースでは長さの制限が可能です。制限を超える場合、超えた部分の値は存在しないので大きな値はuniqueness検証をパスする可能性があります。このようなケースの場合、`ActiveRecord::ValueTooLong`例外をraiseするようになりました。

## MySQLとPostgreSQLでカラムの制限値を超えているとき、`ActiveRecord::ValueTooLong`をraiseするように

すぐ上のSQLiteのところに書いてるやつですね。

## マイグレーションで`#foreign_key`は`table_name_prefix`と`table_name_suffix`を考慮するように

foreign_keyを設定するときに`ActiveRecord::Base.table_name_prefix`と`ActiveRecord::Base.table_name_suffix`を考慮するようになりました。

参考：[#24614](https://github.com/rails/rails/pull/24614)

## SQLiteでPrimaryキーはNOT NULLを強制するように

SQL標準に準拠しました。レガシーアプリケーションだと当然ながら動かなくなる可能性があります。

## データベースのCREATEやDROPが成功したときのコンソール表示を追加

```bash
$ bin/rails db:create
Created database 'blog_development'
Created database 'blog_test'

$ bin/rails db:drop
Dropped database 'blog_development'
Dropped database 'blog_test'
```

## PostgreSQLとMySQLでデータベースコメントが追加できるようになりました

テーブルとカラムとインデックスにアノテーションが書けます。

```rb
create_table :pages, force: :cascade, comment: 'CMS content pages' do |t|
  t.string :path,   comment: 'Path fragment of page URL used for routing'
  t.string :locale, comment: 'RFC 3066 locale code of website language section'
  t.index [:path, :locale], comment: 'Look up pages by URI'
end
```

## TIMEカラム値の日付の部分を切り捨てるための`quoted_time`が追加されました

MariaDBのTIMEカラムのクエリを修正する用のようです。

## ActiveRecordのDelegateに`none?`と`one?`が追加されました

```rb
# When no record is found on the table
Topic.none?  # => true

# When only one record is found on the table
Topic.one?   # => true
```

## MySQLでstrict modeは上書きするのではなくSQL modeを考慮するようになりました

`strict: true`の場合、sql_modeに`STRICT_ALL_TABLES`が追加されます。
`strict: false`の場合、sql_modeから`STRICT_TRANS_TABLES`, `STRICT_ALL_TABLES`, `TRADITIONAL`が取り除かれます。

## サブクラスではabstractクラスで定義されたdefault_scopeが実行されるように

[Execute default_scope defined by abstract class within the scope of subclass by meinac · Pull Request #23666 · rails/rails](https://github.com/rails/rails/pull/23666)

## DatabaseStatementsの`{insert|update|delete}_sql`はdeprecatedになりました

代わりに`{insert|update|delete}`メソッドを使いましょう。

## `has_many :through`がeager loadingするとき、joinするモデルのorderが正しく動作するように

下記の例だと`authors`がeager loadingされるとき、`by_lines`のorderになります。

```rb
class Article < ActiveRecord::Base
  has_many :by_lines, -> { order(:position) }
  has_many :authors, through: :by_lines
end
```

## `:default`オプションがProcのように渡されたら式展開しないように

DBの`NOW()`が使えるようになったりしますね。べんり。

```rb
create_table :posts do |t|
  t.datetime :published_at, default: -> { 'NOW()' }
end
```

## MySQLにおいてtext型とblob型の短縮メソッドを追加

PostgreSQLやSQliteにはありませんが、MySQLはtext型とblob型にも種類があるので指定できるようになりました。べんり。

```rb
create_table :foos do |t|
  t.tinyblob   :tiny_blob
  t.mediumblob :medium_blob
  t.longblob   :long_blob
  t.tinytext   :tiny_text
  t.mediumtext :medium_text
  t.longtext   :long_text
end
```

## PostgreSQLのgeometricデータ型のスキーマダンプをサポート

べんり。

## Autoincrementのprimaryキーを回避するため、デフォルトがnilでbigint型を指定できるようになりました

べんり。

## MySQLDatabaseTasksから`DEFAULT_CHARSET`と`DEFAULT_COLLATION`を削除

http://qiita.com/kamipo/items/d7863f0df24916005657 の対応ですね。べんり。

## unsignedなnumeric型をMySQLでサポート

ようやくunsignedが公式にサポートされました。べんり。

```rb
create_table :foos do |t|
  t.unsigned_integer :quantity
  t.unsigned_bigint  :total
  t.unsigned_float   :percentage
  t.unsigned_decimal :price, precision: 10, scale: 2
end
```

primary keyをunsignedにするケースはこちら。

```rb
create_table :foos, id: :bigint, unsigned: true do |t|
  …
end
```

## Connectionアダプタに`#view`と`#view_exists?`が追加

実装まで追ってないけどMySQLやPostgreSQLのViewが使えるようになったのかな？（要確認）
そうだったらべんりそう。

### 追記

[テストコード](https://github.com/rails/rails/blob/v5.0.0.beta3/activerecord/test/cases/view_test.rb)を読んだら`CREATE VIEW`したやつが取れるのをテストしていたのでView定義に関するメソッドでした。べんり。

## 複合primary keyをサポート

べんり。

```rb
create_table :barcodes, primary_key: ["region", "code"] do |t|
  t.string :region
  t.integer :code
end
```

## MySQLのJSON型をサポート

おお、これ使えるのですか。べんりー。

```rb
create_table :json_data_type do |t|
  t.json :settings
end
```

## `strict: :default`が指定されているときは`sql_mode`はセットしないでください

ﾄﾉｺﾄ。

```rb
# config/database.yml
production:
  adapter: mysql2
  database: foo_prod
  user: foo
  strict: :default
```

## MySQLで `create_table` するときの `:options` を正しくdumpするように

http://qiita.com/kamipo/items/4763bcffce2140f030b3 の修正だと思います。べんり。

## PostgreSQLでStringやTextカラムに対して `:collation` をサポート

```rb
create_table :foos do |t|
  t.string :string_en, collation: 'en_US.UTF-8'
  t.text   :text_ja,   collation: 'ja_JP.UTF-8'
end
```

## MySQLでStringやTextカラムに対して `:collation` や `:charset` をサポート

```rb
create_table :foos do |t|
  t.string :string_utf8_bin, charset: 'utf8', collation: 'utf8_bin'
  t.text   :text_ascii,      charset: 'ascii'
end
```

## `serial`と`bigserial`が正しくdumpされるように

https://github.com/rails/rails/pull/19185 のPRで対応された修正です。

## MySQLで任意のUnicode文字セットをサポートする `SchemaMigration.create_table` が追加

https://github.com/rails/rails/pull/17601 のPR修正分です。これでutf8mb4対応が完全になったのかな？

## MySQLのbigintのprimary keyで `limit` オプションをサポート

```rb
create_table :foos, id: :primary_key, limit: 8 do |t|
end

# or

create_table :foos, id: false do |t|
  t.primary_key :id, limit: 8
end
```

## Time型のカラムの精度に応じた時間文字列をフォーマット & Time型カラムで `presicion` オプションをサポート

https://github.com/rails/rails/pull/18914 のPRです。ミリ秒に対応できるようになる修正のやつです。


# 参考

https://github.com/rails/rails/blob/v5.0.0.rc1/activerecord/CHANGELOG.md