iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

有些資料要事先建立好來使用,比如說點餐系統裡面要先有餐點清單,可以很直覺的新增一張table,把餐點一個個加進去,可是table應該放需要增刪改查的資料,但餐點清單不會在 runtime 時去更動他,放在table就沒這麼適合。也可以把餐點清單放進一個個常數,但是就沒有像是ActiveRecord查詢跟關聯的好用功能,這時候今天的主題ActiveHash就非常好用。

ActiveHash

ActiveHash 是個ruby gem,資料是由hash所構成,假定每個hash都有:id作為key。例如這樣:

#app/models/menu.rb

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可以使用,大家可以看說明文件

建立ActiveRecord關聯

ActiveHash也可以作為上層跟ActiveRecord做關聯,也就是說可以讓
ActiveRecord 的 Model屬於(belongs_to)ActiveHash的 class。

反過來,ActiveHash 不能has_many 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::ActiveRecordExtensionsModel可以跟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號"}> 

#belongs_to_active_hash

如果不想每次建關聯都要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之間的關聯

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時被動態修改本來就是不合理的。


上一篇
[Day 21] 交易 transaction
下一篇
[Day 23] Rake 任務
系列文
關於 Ruby on Rails,我想說的是23

尚未有邦友留言

立即登入留言