0
0

More than 3 years have passed since last update.

【Rails】DB上は文字列だけどモデルでは配列として扱いたい

Last updated at Posted at 2021-09-09

環境情報

  • Rails 5.2.6

やりたいこと

ActiveRecord側ではintegerの配列で扱いたいが、DBにはカンマ区切りの文字列として保存したい

やりかた

fooというテーブルのfoo_idsをintegerの配列として利用したい

テーブル作成

create_table :foos do |t|
  t.string :foo_ids
end

Coderクラス作成

activemodelのattributeの仕組み上、頻繁にdump,loadが呼び出されるので、バリデーションなども行う場合は要注意

class IntegerArray
  def self.dump(object)
    return "" if object.blank?
    object.join(",")
  end

  def self.load(string)
    return [] if string.blank?
    string.split(",").map(&:to_i)
  end
end

モデル作成

class Foo < ApplicationRecord
  serialize :foo_ids, IntegerArray
end

確認

[10] pry(main)> foo = Foo.new                                                                                                                                                                          
[12] pry(main)> foo.foo_ids = [1, 2]                                                                                                                                                                      
=> [1, 2]
[15] pry(main)> foo.save!                                                                                                                                                                                 
   (3.2ms)  BEGIN
  Foo Create (2.7ms)  INSERT INTO `foos` (`foo_ids`) VALUES ('1,2')
   (7.3ms)  COMMIT
=> true
[16] pry(main)> Foo.first   
  Foo Load (2.8ms)  SELECT  `foos`.* FROM `foos` ORDER BY `foos`.`id` ASC LIMIT 1
=> #<Foo:0x00007fbfb7be5ae0 id: 3, foo_ids: [1, 33]>                                           

serializeつかっていいの?

基本的に避けたほうが良いのは同意できるが、パフォーマンスなどの都合でどうしても正規化できない状況もあるのでトレードオフを考慮して使うべきだと思いました。(storeはまだ使い所がわかりません)

また、具体的にどの処理が重いのか検証した記事が少なく、調べてみたいと思います。to be continued...

他の方法

  1. 独自のActiveRecord::Type::Serializedを定義して、serialize毎再実装する(大変だが少しだけ最適化できる)
  2. モデル側にintegerの配列として扱えるメソッド群を用意する(うまくmodule化すれば一番安定?)
  3. composed_ofでValueObjectのように扱う
0
0
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
0
0