ActiveHashとEnumのまとめ
3種類の値を管理する必要があり、複数箇所で使用する予定がある場合にどちらが良いのかを検討する
それぞれの特徴をまとめる
ActiveHash
導入はいいので使い方をまとめる
# in app/models/country.rb
class Country < ActiveHash::Base
self.data = [
{:id => 1, :name => "US"},
{:id => 2, :name => "Canada"}
]
end
# in some view
<%= collection_select :person, :country_id, Country.all, :id, :name %>
delegatedみたいに短縮もできる
# app/models/country.rb
class Country < ActiveHash::Base
end
# app/models/person.rb
class Person < ActiveRecord::Base
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :country, :shortcuts => [:name]
end
# config/initializers/data.rb
Rails.application.config.to_prepare do
Country.data = [
{:id => 1, :name => "US"},
{:id => 2, :name => "Canada"}
]
end
# Using `rails console`
john = Person.new
john.country_name = "US"
# Is the same as doing `john.country = Country.find_by_name("US")`
john.country_name
# Will return "US", and is the same as doing `john.country.try(:name)`
アソシエーション
自分の会社のモデルでは定義されている場所とそうでない場所が分かれている
会社のモデルでは次のように記述している
include ActiveHash::Enum
(省略)
enum_accessor :カラム名
ActiveHashは、各レコードに定数を設定することで、そのデータをEnumerationで公開することができます。これにより、ActiveHashクラスに設定された定数を介して、コード内でレコードにアクセスすることができます。
定数として使用するフィールドは、フィールド名を引数に取るenum_accessorを使用して設定します。
class Country < ActiveHash::Base
include ActiveHash::Enum
self.data = [
{:id => 1, :name => "US", :capital => "Washington, DC"},
{:id => 2, :name => "Canada", :capital => "Ottawa"},
{:id => 3, :name => "Mexico", :capital => "Mexico City"}
]
enum_accessor :name
end
>> Country::US.capital
=> "Washington DC"
>> Country::MEXICO.id
=> 3
>> Country::CANADA
=> #<Country:0x10229fb28 @attributes={:name=>"Canada", :id=>2}
class Town < ActiveHash::Base
include ActiveHash::Enum
self.data = [
{:id => 1, :name => "Columbus", :state => "NY"},
{:id => 2, :name => "Columbus", :state => "OH"}
]
enum_accessor :name, :state
end
>> Town::COLUMBUS_NY
>> Town::COLUMBUS_OH
定数は、まず単語以外の文字をすべて削除し、その結果をアップスケールして形成されます。つまり、"Blazing Saddles", "ReBar", "Mike & Ike", "Ho! Ho!Ho!" は BLAZING_SADDLES、REBAR、MIKE_IKE、HO_HO_HO となります。
enum_accessor に指定するフィールドは、一意なデータ値を持つ必要がある。
enum
概ね知っていることが多い
このRailsアプリのPostモデルにはさまざまなステータスがあるので、そのうち指定のステータスのレコードだけを取り出したくなるでしょう。Railsにはこのクエリを解決する動的なメソッドが追加されています。
たとえばステータスがpublishedのpostをすべてフェッチするなら、RailsのコントローラでPost.where(status: "published")のように書くことも一応可能です。
そのように書く代わりに、Postでpublishedメソッドをスコープとして使えます。Railsは、enumにあるすべてのステータスごとに、ステータスと同じ名前のクラスメソッドを動的に追加します。この場合、Postモデルに#draft、#published、#archived、#trashedメソッドが生成されます。
Rails 6では、enumのスコープの否定条件も利用できます。ステータスがpublishedでないpostをすべてフェッチするには、以下のようにpublishedメソッド名の冒頭にnot_を追加できます。
Post.published
select "posts".* from "posts" where "posts"."status" = $1 [["status", 1]]
enumの値だけだと意味がわからないこともあるので、enum名にプレフィックスやサフィックスを適用する方がよいでしょう。ここでは、アプリケーションでenumとして定義されたstatusカラムを持つUserモデルを考えてみましょう。
class User < ApplicationRecord
enum :status, { invited: 0, active: 1, deactivated: 2 }
end
# 次のように書く
class User < ApplicationRecord
enum :status, { invited: 0, active: 1, deactivated: 2 }, suffix: true
end
user.invited_status?
user.active_status!
User.deactivated_status
class User < ApplicationRecord
enum :status, { invited: 0, active: 1, deactivated: 2 }, prefix: true
end
プレフィックスやサフィックスのないenumを定義すると、Post.freeやpost.published?やpost.premium!がどちらのカラムを参照しているかがわかりにくくなり、開発者が戸惑ってしまいます。
代わりに、以下のようにプレフィックスやサフィックスをメソッドに追加して、必要なメソッドを呼び出せるようにできます。
enumの更新・確認
enum VS active_hashではなく、
数字を1つのカテゴリ名に変換したい場合はenumを使用し、
カテゴリ名以外に情報を持たせたい場合やカテゴリの個数が多い場合ははActive _hashを使用する
従ってenum型を採用するか否かという問題になる