跳至內容 跳至搜尋

Active Record – 物件關聯對應在 Rails 中

Active Record 將類別連接到關聯式資料庫表格,以建立幾乎零組態的應用程式持續性層。此函式庫提供一個基礎類別,在子類別化時,設定新類別與資料庫中現有表格之間的對應。在應用程式的脈絡中,這些類別通常稱為模型。模型也可以連接到其他模型;這會透過定義關聯來完成。

Active Record 仰賴命名,它使用類別和關聯名稱來建立各自資料庫表格和外來金鑰欄位之間的對應。儘管這些對應可以明確定義,但建議遵循命名慣例,特別是在開始使用程式庫時。

您可以在 Active Record 基礎 指南中閱讀更多關於 Active Record 的資訊。

簡要說明一些主要功能

  • 類別和表格、屬性和欄位之間的自動對應。

    class Product < ActiveRecord::Base
    end
    

    Product 類別會自動對應到名為「products」的表格,看起來可能像這樣

    CREATE TABLE products (
      id bigint NOT NULL auto_increment,
      name varchar(255),
      PRIMARY KEY  (id)
    );
    

    這也會定義下列存取器:Product#nameProduct#name=(new_name)

    了解更多

  • 關聯 由簡單類別方法定義的物件之間的關聯。

    class Firm < ActiveRecord::Base
      has_many   :clients
      has_one    :account
      belongs_to :conglomerate
    end
    

    了解更多

  • 聚合 值物件。

    class Account < ActiveRecord::Base
      composed_of :balance, class_name: 'Money',
                  mapping: %w(balance amount)
      composed_of :address,
                  mapping: [%w(address_street street), %w(address_city city)]
    end
    

    了解更多

  • 驗證規則,對於新物件或現有物件可能不同。

    class Account < ActiveRecord::Base
      validates :subdomain, :name, :email_address, :password, presence: true
      validates :subdomain, uniqueness: true
      validates :terms_of_service, acceptance: true, on: :create
      validates :password, :email_address, confirmation: true, on: :create
    end
    

    了解更多

  • 回呼 可用於整個生命週期(實體化、儲存、銷毀、驗證等)。

    class Person < ActiveRecord::Base
      before_destroy :invalidate_payment_plan
      # the `invalidate_payment_plan` method gets called just before Person#destroy
    end
    

    了解更多

  • 繼承 層級。

    class Company < ActiveRecord::Base; end
    class Firm < Company; end
    class Client < Company; end
    class PriorityClient < Client; end
    

    了解更多

  • 交易.

    # Database transaction
    Account.transaction do
      david.withdrawal(100)
      mary.deposit(100)
    end
    

    了解更多

  • 欄位、關聯和聚合的反射。

    reflection = Firm.reflect_on_association(:clients)
    reflection.klass # => Client (class)
    Firm.columns # Returns an array of column descriptors for the firms table
    

    了解更多

  • 透過簡單的轉接器進行資料庫抽象。

    # connect to SQLite3
    ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'dbfile.sqlite3')
    
    # connect to MySQL with authentication
    ActiveRecord::Base.establish_connection(
      adapter:  'mysql2',
      host:     'localhost',
      username: 'me',
      password: 'secret',
      database: 'activerecord'
    )
    

    了解更多,並閱讀內建支援 MySQLPostgreSQLSQLite3 的資訊。

  • 支援 Log4rLogger 的記錄。

    ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
    ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
    
  • 使用遷移進行與資料庫無關的架構管理。

    class AddSystemSettings < ActiveRecord::Migration[7.1]
      def up
        create_table :system_settings do |t|
          t.string  :name
          t.string  :label
          t.text    :value
          t.string  :type
          t.integer :position
        end
    
        SystemSetting.create name: 'notice', label: 'Use notice?', value: 1
      end
    
      def down
        drop_table :system_settings
      end
    end
    

    了解更多

哲學

Active Record 是物件關係對應 (ORM) 模式 的實作,名稱與 Martin Fowler 所描述的相同

「封裝資料庫表格或檢視中一列的物件,封裝資料庫存取,並在該資料上加入網域邏輯。」

Active Record 嘗試提供一個連貫的封裝,作為物件關係對應不便之處的解決方案。此對應的主要準則是最小化建構真實世界網域模型所需的程式碼數量。這透過依賴許多慣例而得以實現,這些慣例讓 Active Record 能夠從最少的明確指示中推論出複雜的關係和結構。

慣例勝於設定

  • 沒有 XML 檔案!

  • 大量的反射和執行時間延伸

  • 魔法本身並非一個壞字

承認資料庫

  • 讓您在特殊情況和效能方面下降到 SQL

  • 不會嘗試複製或取代資料定義

下載和安裝

最新版本的 Active Record 可以使用 RubyGems 安裝

$ gem install activerecord

原始碼可以作為 GitHub 上 Rails 專案的一部分下載

授權

Active Record 在 MIT 授權下發布

支援

API 文件位於

Ruby on Rails 專案的錯誤報告可以提交到這裡

功能要求應在這裡的 rails-core 郵件清單中討論

命名空間
方法
D
E
G
L
M
S
U
V
包含的模組

常數

MigrationProxy = Struct.new(:name, :version, :filename, :scope) do def initialize(name, version, filename, scope) super @migration = nil end def basename File.basename(filename) end delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration private def migration @migration ||= load_migration end def load_migration Object.send(:remove_const, name) rescue nil load(File.expand_path(filename)) name.constantize.new(name, version) end end
 

MigrationProxy 用於延後載入實際的遷移類別,直到需要時才載入

Point = Struct.new(:x, :y)
 
UnknownAttributeError = ActiveModel::UnknownAttributeError
 

Active Model UnknownAttributeError

當透過大量指派提供未知屬性時引發。

class Person
  include ActiveModel::AttributeAssignment
  include ActiveModel::Validations
end

person = Person.new
person.assign_attributes(name: 'Gorby')
# => ActiveModel::UnknownAttributeError: unknown attribute 'name' for Person.

屬性

[RW] application_record_class
[RW] async_query_executor
[RW] before_committed_on_all_records
[RW] belongs_to_required_validates_foreign_key
[RW] commit_transaction_on_non_local_return
[R] db_warnings_action
[RW] db_warnings_ignore
[R] default_timezone
[RW] disable_prepared_statements
[RW] index_nested_attribute_errors
[RW] lazily_load_schema_cache
[RW] maintain_test_schema
[RW] query_transformers
[RW] raise_on_assign_to_attr_readonly
[RW] reading_role
[RW] run_after_transaction_callbacks_in_order_defined
[RW] schema_cache_ignored_tables
[RW] writing_role

類別公開方法

db_warnings_action=(action)

# File activerecord/lib/active_record.rb, line 211
def self.db_warnings_action=(action)
  @db_warnings_action =
    case action
    when :ignore
      nil
    when :log
      ->(warning) do
        warning_message = "[#{warning.class}] #{warning.message}"
        warning_message += " (#{warning.code})" if warning.code
        ActiveRecord::Base.logger.warn(warning_message)
      end
    when :raise
      ->(warning) { raise warning }
    when :report
      ->(warning) { Rails.error.report(warning, handled: true) }
    when Proc
      action
    else
      raise ArgumentError, "db_warnings_action must be one of :ignore, :log, :raise, :report, or a custom proc."
    end
end

default_timezone=(default_timezone)

決定從資料庫中提取日期和時間時,是否使用 Time.utc(使用:utc)或 Time.local(使用:local)。預設設定為:utc。

# File activerecord/lib/active_record.rb, line 196
def self.default_timezone=(default_timezone)
  unless %i(local utc).include?(default_timezone)
    raise ArgumentError, "default_timezone must be either :utc (default) or :local."
  end

  @default_timezone = default_timezone
end

disconnect_all!()

明確關閉所有資料庫連線,在所有池中。

# File activerecord/lib/active_record.rb, line 476
def self.disconnect_all!
  ConnectionAdapters::PoolConfig.disconnect_all!
end

eager_load!()

# File activerecord/lib/active_record.rb, line 465
def self.eager_load!
  super
  ActiveRecord::Locking.eager_load!
  ActiveRecord::Scoping.eager_load!
  ActiveRecord::Associations.eager_load!
  ActiveRecord::AttributeMethods.eager_load!
  ActiveRecord::ConnectionAdapters.eager_load!
  ActiveRecord::Encryption.eager_load!
end

gem_version()

傳回目前載入的 Active Record 版本,為 Gem::Version

# File activerecord/lib/active_record/gem_version.rb, line 5
def self.gem_version
  Gem::Version.new VERSION::STRING
end

global_executor_concurrency=(global_executor_concurrency)

設定 global_executor_concurrency。此設定值只能與全域執行緒池非同步查詢執行器搭配使用。

# File activerecord/lib/active_record.rb, line 278
def self.global_executor_concurrency=(global_executor_concurrency)
  if self.async_query_executor.nil? || self.async_query_executor == :multi_thread_pool
    raise ArgumentError, "`global_executor_concurrency` cannot be set when using the executor is nil or set to multi_thead_pool. For multiple thread pools, please set the concurrency in your database configuration."
  end

  @global_executor_concurrency = global_executor_concurrency
end

legacy_connection_handling=(_)

# File activerecord/lib/active_record.rb, line 245
  def self.legacy_connection_handling=(_)
    raise ArgumentError, <<~MSG.squish
      The `legacy_connection_handling` setter was deprecated in 7.0 and removed in 7.1,
      but is still defined in your configuration. Please remove this call as it no longer
      has any effect."
    MSG
  end

marshalling_format_version()

# File activerecord/lib/active_record.rb, line 457
def self.marshalling_format_version
  Marshalling.format_version
end

marshalling_format_version=(value)

# File activerecord/lib/active_record.rb, line 461
def self.marshalling_format_version=(value)
  Marshalling.format_version = value
end

suppress_multiple_database_warning()

# File activerecord/lib/active_record.rb, line 395
  def self.suppress_multiple_database_warning
    ActiveRecord.deprecator.warn(<<-MSG.squish)
      config.active_record.suppress_multiple_database_warning is deprecated and will be removed in Rails 7.2.
      It no longer has any effect and should be removed from the configuration file.
    MSG
  end

suppress_multiple_database_warning=(value)

# File activerecord/lib/active_record.rb, line 402
  def self.suppress_multiple_database_warning=(value)
    ActiveRecord.deprecator.warn(<<-MSG.squish)
      config.active_record.suppress_multiple_database_warning= is deprecated and will be removed in Rails 7.2.
      It no longer has any effect and should be removed from the configuration file.
    MSG
  end

unknown

指定呼叫資料庫查詢的方法是否應記錄在其相關查詢下方。預設為 false。

# File activerecord/lib/active_record.rb, line 298
singleton_class.attr_accessor :verbose_query_logs

version()

傳回目前載入的 Active Record 版本,為 Gem::Version

# File activerecord/lib/active_record/version.rb, line 7
def self.version
  gem_version
end