Rails5から使えるActiveRecord便利機能


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

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

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

MySQLでPrepared statesmentsをサポート

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

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

schema.rbcreate_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_keytable_name_prefixtable_name_suffixを考慮するように

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

参考:#24614

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

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

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

$ 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でデータベースコメントが追加できるようになりました

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

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?が追加されました

# 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

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

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

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

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

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

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

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

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

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

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

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_CHARSETDEFAULT_COLLATIONを削除

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

unsignedなnumeric型をMySQLでサポート

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

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にするケースはこちら。

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

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

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

追記

テストコードを読んだらCREATE VIEWしたやつが取れるのをテストしていたのでView定義に関するメソッドでした。べんり。

複合primary keyをサポート

べんり。

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

MySQLのJSON型をサポート

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

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

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

トノコト。

# 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 をサポート

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 をサポート

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

serialbigserialが正しく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 オプションをサポート

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です。ミリ秒に対応できるようになる修正のやつです。

参考