@vividmuimui
社内勉強会資料 LT資料 2017/11/03
この資料は2017/11/03時点のもので、Rails5.2が出る前のものです。
資料内でGemを導入していますが、Rails5.2では必要なくなっています。
rails5で入った機能
分かりやすかった記事
実装する時に確実に見るやつ
実際実装したのを例にします。
class EmailType < ActiveModel::Type::String
# DBに入れる・検索する時にどう変換するか
def serialize(value)
normalize(super)
end
# DBから取り出す時にどう変換するか
# def deserialize(value); end
private
# setterでどう変換するか
def cast_value(value)
normalize(super)
end
def normalize(value)
return unless value
value.downcase.remove(/\A[[:^graph:]]*/).remove(/[[:^graph:]]*\z/)
end
end
ActiveRecord::Type.register(:email, EmailType)
class User < ApplicationRecord
# attribute :field, :type
attribute :email, :email
end
設定終わり
検索する時にserializeされて検索される
(main)> User.find_by(email: " SAMPLE@EXAMPLE.COM ")
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`email` = 'sample@example.com' LIMIT 1
保存するときもserializeされる
(main)> FactoryBot.create(:user, email: " SAMPLE@EXAMPLE.COM ").email
(0.4ms) BEGIN
SQL (0.3ms) INSERT INTO `users` (`uid`, `identifier`, `email`, `password_digest`, `activated`, `activated_at`, `created_at`, `updated_at`) VALUES ('ViyL8xm9nhe4z4jZVRTwlg', '1ef4', 'sample@example.com', '$2a$10$0OEucfnPTeE74NCZ9nz25uoCXyQInJEMVSlBVB657U8QG0NsLKvde', 1, '2017-11-03 13:58:43', '2017-11-03 13:58:43', '2017-11-03 13:58:43')
(8.5ms) COMMIT
=> "sample@example.com"
setter等では, cast_value(#cast)が呼ばれる
User.new(email: " SAMPLE@EXAMPLE.COM ").email
=> "sample@example.com"
(main)> a = User.new
=> #<User:0x00007fec9402c118 ....
(main)> a.email = " SAMPLE@EXAMPLE.COM "
=> " SAMPLE@EXAMPLE.COM "
(main)> a.email
=> "sample@example.com"
現状のrailsでは ActiveRecord
でしか使えず、ActiveModelなobjectでは使えない
つい最近、ActiveModelでも動くように実装され始めているようだが、現時点では使えない
https://github.com/rails/rails/pull/30920
ここらへん読んで理解しつつつactive_model_attributes
gemを入れる
https://github.com/rails/rails/pull/26728
https://karolgalanciak.com/blog/2016/12/04/introduction-to-activerecord-and-activemodel-attributes-api/
gem "active_model_attributes"
class EmailType < ActiveModel::Type::String
# DBに入れる・検索する時にどう変換するか
def serialize(value)
normalize(super)
end
# DBから取り出す時にどう変換するか
# def deserialize(value); end
private
# setterでどう変換するか
def cast_value(value)
normalize(super)
end
def normalize(value)
return unless value
value.downcase.remove(/\A[[:^graph:]]*/).remove(/[[:^graph:]]*\z/)
end
end
ActiveModel::Type.register(:email, EmailType) # ActiveRecordではなくActiveModel
class SomeModel
include ActiveModel::Model
include ActiveModelAttributes
attribute :email, :email
end
設定終わり
(main)> SomeModel.new(email: " SAMPLE@EXAMPLE.COM ").email
=> "sample@example.com"
(main)> a = SomeModel.new
=> #<SomeModel:0x00007fec933324f8>
(main)> a.email = " SAMPLE@EXAMPLE.COM "
=> " SAMPLE@EXAMPLE.COM "
(main)> a.email
=> "sample@example.com"
before_validationでゴニョゴニョしてるときとか、
今回のような、ユーザの入力をnormalizeしたいときとかにはだいぶ有用そうだった
だいぶ便利なので、ほかにも使いみちは色々ありそう