有些資料要事先建立好來使用,比如說點餐系統裡面要先有餐點清單,我們可以選擇直覺的新增 table,把餐點一個個加進去,可是table
應該放需要增刪改查
的資料。但正常狀況餐點清單不會在 runtime (程式執行)時去更動他,放在table就沒這麼適合。不建立table,也可以把餐點清單放進一個個常數,但是就沒有像是ActiveRecord
查詢跟關聯的好用功能,這時候今天的主題ActiveHash就非常好用。
ActiveHash 是個ruby gem,資料是由hash所構成,假定每個hash都有:id
作為key。例如這樣:
class Menu < ActiveHash::Base
self.data = [
{id: 1, name: "Spaghetti", price: 168},
{id: 2, name: "Soup", price: 99},
{id: 3, name: "Pizza", price: 145},
]
end
建立一個array,裡面每個元素都是一筆hash形式的資料,再把這個array塞給self.data
,要注意id
必須是唯一,如果沒有設定id的話,ActiveHash會自動幫你加上按照順序加上流水號,為了方便閱讀,建議自己加id。
Menu.count
# => 3
Menu.create(name: 'noodle', price: 80) #用create新增菜單在記憶體裡
# => #<Menu:0x00007fa5db031618 @attributes={:name=>"noodle", :price=>80, :id=>4}>
Menu.all #多了一筆剛才新增的'noodle'菜單
# => [#<Menu:0x00007fd380f195e0 @attributes={:id=>1, :name=>"Spaghetti", :price=>168}>, #<Menu:0x00007fd380f9fed8 @attributes={:id=>2, :name=>"Soup", :price=>99}>, #<Menu:0x00007fd380f9f028 @attributes={:id=>3, :name=>"Pizza", :price=>145}>, #<Menu:0x00007fd380fd70e0 @attributes={:name=>"noodle", :price=>80, :id=>4}>]
Menu.find 3 #找第三筆菜單
# => #<Menu:0x00007fa5d77b78f0 @attributes={:id=>3, :name=>"Pizza", :price=>145}>
Menu.where(price: 99) #找價格是99的餐點
# => [#<Menu:0x00007fa5d77c43e8 @attributes={:id=>2, :name=>"Soup", :price=>99}>]
很像在使用Model吧
create
會把新增資料存進記憶體,用.all
可以看到原有跟新增的資料,create
出來的資料在console關掉後就會不見。
還有一些不錯的語法像是find_by
可以使用,大家可以看說明文件。
ActiveHash
也可以作為上層跟ActiveRecord做關聯,也就是說可以讓
ActiveRecord 的 Model屬於(belongs_to)
ActiveHash的 class。
反過來,ActiveHash
不能belongs_to
ActiveRecord
假設我是三家店的老闆,每家店都有很多客戶:
class Shop < ActiveHash::Base
self.data = [
{id: 1, name: "飾品店", address: '內湖路一段111號'},
{id: 2, name: "桌遊店", address: '台灣大道二段5號'},
{id: 3, name: "Apple", address: '華映路1號'},
]
end
class Customer < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :shop
end
透過extend ActiveHash::Associations::ActiveRecordExtensions
讓Model
可以跟ActiveHash
建立belongs_to
關聯。
可以在console建立customer跟shop的關聯
Customer.create(name: '放韓假', shop_id: 3) #在create的時候指定shop_id
#=> #<Customer id: 2, name: "放韓假", phone: nil, created_at: "2019-10-19 09:57:55", updated_at: "2019-10-19 09:57:55", shop_id: 3>
Customer.last.shop
# => #<Shop:0x00007fae9d3380d0 @attributes={:id=>3, :name=>"Apple", :address=>"華映路1號"}>
如果不想每次建關聯都要includeActiveHash::Associations
,可以直接在app/models/application_record.rb
貼上一行code:
ActiveRecord::Base.extend ActiveHash::Associations::ActiveRecordExtensions
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
剛才Customer Model改用belongs_to_active_hash
class Customer < ApplicationRecord
belongs_to_active_hash :shop
end
搞定!!
把ActiveHash::Associations
這個 module include 進ActiveHash class
,就可以建立跟另一個ActiveHash class
的關聯:
class Country < ActiveHash::Base
include ActiveHash::Associations
has_many :people
end
class Person < ActiveHash::Base
include ActiveHash::Associations
belongs_to :country
has_many :pets
end
class Pet < ActiveRecord::Base
end
值得注意的是,作者有說他不會讓ActiveHash
成為ActiveRecord
的子關聯,這樣對DB很麻煩。我也認同,因為原本ActiveHash
的資料是寫死的,你想讓他可以在runtime時被動態修改本來就是不合理的。