Ruby/Rails syntax
  • Index
  • chap 1
  • chap 2
  • chap 3
  • chap 4
  • Enterprise Rails - big picture
  • Nokogiri
  • ActiveRecord - 進階功能
  • pack & unpack
  • performance
  • rails engine
  • jsonb / json / hstore
  • Deploy
  • Polymorphism/Polymorphic Associations
  • relationship
  • rvm / ENV
  • Auth
  • DB related
  • TODO N+1
  • SQL view
  • module
  • api + create-react-app
  • ONE_LINE
  • Delete & destroy association
Powered by GitBook
On this page
  • 單一表格繼承STI(Single-table inheritance)
  • 交易Transactions
  • 序列化Serialize
  • Store

Was this helpful?

ActiveRecord - 進階功能

PreviousNokogiriNextpack & unpack

Last updated 5 years ago

Was this helpful?

單一表格繼承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

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

交易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"}

STI is problematic when type change.

Others

https://ihower.tw/rails/activerecord-others.html
http://blog.arkency.com/2013/07/sti/
https://about.futurelearn.com/blog/refactoring-rails-sti/
https://robots.thoughtbot.com/whats-the-deal-with-rails-polymorphic-associations