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?