ActiveRecord - 進階功能
https://ihower.tw/rails/activerecord-others.html
單一表格繼承STI(Single-table inheritance)
只用一個table儲存繼承體系中的物件,搭配一個type欄位(string)用來指名Class名稱。
以下的contacts 資料表有欄位叫做type,那麼這三個Models實際上就會共用contacts一個table。
Company/Person class 繼承到父類別的validates_presence_of :name。
class Contact < ActiveRecord::Base
validates_presence_of :name
end
class Company < Contact
end
class Person < Contact
end
contact = Person.create( :name => "ihower")
contact.type # "Person"
STI最大的問題在於欄位的浪費。建議不要使用這個功能,讓個別的class有自己的資料表。要關閉STI,請父類別加上self.abstract_class = true
這樣Company和Person就需要有自己的Migrations建立companies和people資料表了。
class Contact < ActiveRecord::Base
self.abstract_class = true
validates_presence_of :name
end
class Company < Contact
end
class Person < Contact
end
因此,Active Record看見column名稱為type,自動假設你用STI,產生問題。
ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: PowerUser is not a subclass of User
STI is problematic when type change. http://blog.arkency.com/2013/07/sti/
Example: Admin < User. Is it possible that my User will no longer be an Admin. Yes! Ah, so being admin is more likely a role that you have in organization. Inheritance won’t do.
Refactor from STI
https://about.futurelearn.com/blog/refactoring-rails-sti/
Others https://robots.thoughtbot.com/whats-the-deal-with-rails-polymorphic-associations
交易Transactions
兩個動作都成功的情況下才會將這筆操作寫入資料庫,否則在其中一個動作失敗,就會放棄所有已做的操作。
要使用create!
而不是create
,因為前者驗證失敗才會丟出例外,好讓整個交易失敗。
User.transaction do
User.create!(:name => 'ihower')
Feed.create!
end
序列化Serialize
將object轉換成一個可被db儲存的純文字形態。
但是缺點是Serialize資料就失去了透過db查詢索引的功效,無法SQL的where條件索引。
class User < ActiveRecord::Base
serialize :settings
end
> user = User.create(settings: { "sex" => "male", "url" => "foo" })
> User.find(user.id).settings # => { "sex" => "male", "url" => "foo" }
Store
Store又在包裹了Serialize功能,讓你可以將某個欄位指定儲存為Hash值。
class User < ActiveRecord::Base
store :settings, :accessors => [:sex, :url]
end
> user = User.new(:sex => "male", :url => "http://example.com")
> user.sex => "male"
> user.url => "http://example.com"
> user.settings => {:sex => "male", :url => "http://example.com"}
> user.settings[:food] = "pizza"
> user.settings
=> {:sex => "male", :url => "http://example.com", :food => "pizza"}
Last updated
Was this helpful?