Active Record Basics

翻譯自SUN官方文檔
Topics
主題
• What is Active Record?
什麼是Active Record?
• ActiveRecord Object Creation
ActiveRecord對象創建
• Find operation
Find方法
• Dynamic Attribute-based Finders
動態地基於屬性的Finder
• Validation
驗證
• Migration
遷移
• Callbacks
回滾
• Exception Handling
異常控制

What is Active Record?
What is Active Record?
• Active Record is a Ruby library that provides mapping between business objects and database tables
Active Record是一個提供業務對象和數據庫表之間映射關係的Ruby庫
> Accessing, saving, creating, updating operations in your Rails code are performed by Active Record
Rails代碼裏的增刪改查操作由Active Record執行
• It‘s an implementation of the object-relational mapping (ORM) pattern by the same name as described by Martin Fowler:
它實現了對象關係映射(ORM)模型,通過相同的命名由Martin Fowler:
> "An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data."
“一個對象,就是數據庫表或視圖裏的一行,封裝了數據庫鏈接,和數據的邏輯域”
• Contains domain logic
包含邏輯域

Major Features
主要特性
• Automated mapping between classes and tables, attributes and columns.
在類和表,屬性和列之間自動映射
• Validation rules that can differ for new or existing objects.
驗證規則可以區別新舊對象
• Callbacks as methods or queues on the entire lifecycle (instantiation, saving, destroying, validating, etc).
方法或隊列的在一個完整生命週期裏可以回滾
• Observers for the entire lifecycle
生命週期的觀察者
• Transaction support on both a database and object level.
數據庫和對象層都有事務支持
• Reflections on columns, associations, and aggregations
反射
• Direct manipulation (instead of service invocation)
直接操作
• Database abstraction through simple adapters (~100 lines) with a shared connector
通過簡單的adapter實現數據抽象
• Logging support for Log4r and Logger
Log4r和Logger的日誌支持
• Associations between objects controlled by simple meta-programming macros.
通過簡單的元編程實現對象控制的聯合
• Aggregations of value objects controlled by simple meta-programming macros.
通過簡單的元編程實現對象控制的聚合
• Inheritance hierarchies
繼承的分層

Automatic Mapping between Classes and Tables
類和表之間的自動映射
Mapping between Classes and Tables
• Class definition below is automatically mapped to the table named “products”
下面的類自動映射到命名爲“products”的表
  1. class Product < ActiveRecord::Base
  2. end
• Schema of “products” table
數據模型的“products”表
  1. CREATE TABLE products (
  2. id int(11) NOT NULL auto_increment,
  3. name varchar(255),
  4. PRIMARY KEY (id)
  5. );
Active Record Definition & Domain Logic
Active Record定義和邏輯域
• Class definition below is automatically mapped to the table named “products”
class Product < ActiveRecord::Base
end
• Active Record typically contain domain logic
典型的Active Record包括邏輯域
  1. class Product < ActiveRecord::Base
  2. def my_business_method
  3. # Whatever business logic
  4. end
  5. end
Attributes
屬性
• Active Record objects don‘t specify their attributes directly, but rather infer them from the table definition with which they‘re linked.
Active Record對象並不直接指定他們的屬性,而是從相關的表的定義中推斷
• Adding, removing, and changing attributes and their type is done directly in the database.
添加,刪除和改變屬性和類型會直接在數據庫裏完成
• Any change is instantly reflected in the Active Record objects.
任何改變將立刻在Active Record裏產生影響

ActiveRecord Object Creation, Update, Delete
ActiveRecord對象的創建,修改和刪除
ActiveRecord Objects Can Be Created in 3 Different Ways
ActiveRecord對象能夠由三種途徑創建
• Constructor parameters in a hash
構造函數在一個hash
  1. user = User.new(:name => "David":occupation => "Artist")
• Use block initialization
用block初始化
  1. user = User.new do |u|
  2. u.name = "David"
  3. u.occupation = "Code Artist"
  4. end
• Create a bare object and then set attributes
創建一個裸體對象,然後設置屬性
  1. user = User.new
  2. user.name = "David"
  3. user.occupation = "Code Artist"
ActiveRecord Objects Can Be Saved
ActiveRecord對象能夠被保存
• Use save instance method - a row is added to the table
用save方法 - 一行將被添加到數據庫
  1. user = User.new(:name => "David":occupation => "Artist")
  2. user.save

ActiveRecord Find Operation
ActiveRecord的Find操作
find Method
find方法
• find is a class method
find是一個類方法
> In the same way, new and create are class methods
同理,new和create也是類方法
> You use it with a ActiveRecord class (not with an object instance)
你使用它用ActiveRecord類(而不是實例變量)
>Product.find(..)

Find Operation
Find操作
• Find operates with four different retrieval approaches:
Find操作有四個不同的實現方法:
> Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised.
Find by id - 可以是一個指定的id(1),一個id列表(1, 5, 6), 或者是一個id數組([5, 6, 10]).如果一條記錄也找不到,會拋出RecordNotFound異常
> Find first - This will return the first record matched by the options used
Find first - 返回第一條匹配的記錄
> Find last - This will return the last record matched by the options used.
Find last - 返回最後一條匹配的記錄
> Find all - This will return all the records matched by the options used. If no records are found, an empty array is returned.
Find all - 返回所有匹配的記錄。如果找不到記錄,返回一個空數組

Find Criteria
Find準則
• :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]
:conditions - 一條SQL語句,比如"administrator = 1" 或者 [ "user_name = ?", username ]
• :order
• :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
:group - 一個需要被分組的屬性名。用GROUP BY SQL語句
• :limit - An integer determining the limit on the number of rows that should be returned.
:limit - 給一個整數決定需要返回的行數
• :offset - An integer determining the offset from where the rows should be fetched.
:offset - 給一個整數決定哪幾行被分離。
• :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s).
:joins - 附加一個SQL語句,如"LEFT JOIN comments ON comments.post_id = id"(必須的)或者由同一個格式命名
• :include - Names associations that should be loaded alongside. The symbols named refer to already defined associations.
• :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not include the joined columns.
• :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name of a database view).
• :readonly - Mark the returned records read-only so they cannot be saved or updated.
• :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". :lock => true gives connection‘s default exclusive lock, usually "FOR UPDATE".
Examples: Find by id
  1. Person.find(1) # returns the object for ID = 1
  2. Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
  3. Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
  4. Person.find([1]) # returns an array for the object with ID = 1
  5. Person.find(1, :conditions => "administrator = 1",
  6. :order => "created_on DESC")
Examples: Find first
  1. Person.find(:first# returns the first object fetched
  2. # by SELECT * FROM people
  3. Person.find(:first:conditions => [ "user_name = ?", user_name])
  4. Person.find(:first:order => "created_on DESC":offset => 5)
Example: Find all
  1. Person.find(:all# returns an array of objects for all the
  2. rows fetched by SELECT * FROM people
  3. Person.find(:all:conditions => [ "category IN (?)",
  4. categories], :limit => 50)
  5. Person.find(:all:conditions => { :friends => ["Bob",
  6. "Steve""Fred"] }
  7. Person.find(:all:offset => 10, :limit => 10)
  8. Person.find(:all:include => [ :account:friends ])
  9. Person.find(:all:group => "category")
Find with lock
• Imagine two concurrent transactions: each will read person.visits == 2, add 1 to it, and save, resulting in two saves of person.visits = 3. By locking the row, the second transaction has to wait until the first is finished; we get the expected person.visits == 4.
  1. Person.transaction do
  2. person = Person.find(1, :lock => true)
  3. person.visits += 1
  4. person.save!
  5. end
Conditions
• Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
條件能夠被賦予字符串,數組,或者hash
> The array form is to be used when the condition input is tainted and requires sanitization.
> The string form can be used for statements that don‘t involve tainted data.
> The hash form works much like the array form, except only equality and range is possible. Examples:
Examples: Conditions
• Array form
> User.find(:all, :conditions=>["hobby=? AND name=?", 'swimming', 'Tom']
• String form
> User.find(:all, :conditions=>"hobby='swimming'", :order=>"hobby DESC, age")
• Hash form
> User.find(:all, :conditions=>{:hobby=>'swimming', :name=>'Tom'}, :order=>"hobby DESC, age")

Dynamic Attributebased Finders
Dynamic Attribute-based Finders
• Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL.
• They work by appending the name of an attribute to find_by_ or find_all_by_, so you get finders like
Person.find_by_user_name, Person.find_all_by_last_name, and Payment.find_by_transaction_id.

Dynamic Find Operation
• So instead of writing Person.find(:first, :conditions => ["user_name = ?", user_name]), you just do Person.find_by_user_name(user_name).
• And instead of writing Person.find(:all, :conditions => ["last_name = ?", last_name]), you just do Person.find_all_by_last_name(last_name).


ActiveRecord Validation
ActiveRecord::Validations
• Validation methods
  1. class User < ActiveRecord::Base
  2. validates_presence_of :username:level
  3. validates_uniqueness_of :username
  4. validates_oak_id :username
  5. validates_length_of :username:maximum => 3, :allow_nil
  6. validates_numericality_of :value:on => :create
  7. end
Validation


ActiveRecord::Validations
• Active Records implement validation by overwriting Base#validate (or the variations, validate_on_create and validate_on_update).
Active Records實現了驗證通過重寫Base#validate
  1. class Person < ActiveRecord::Base
  2. protected
  3. def validate
  4. errors.add_on_empty %w( first_name last_name )
  5. errors.add("phone_number""has invalid format"unless phone_number =~ /[0-9]*/
  6. end
  7. def validate_on_create # is only run the first time a new object is saved
  8. unless valid_discount?(membership_discount)
  9. errors.add("membership_discount""has expired")
  10. end
  11. end
  12. end

ActiveRecord Migration
ActiveRecord Migration
• Manage the evolution of a schema used
 > It’s a solution to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to push that change to other developers and to the production server.
這是個解決添加成員在本地數據庫的方法
• You can describe the transformations in self-contained classes that can be checked into version control systems and executed against another database that might be one, two, or five versions behind.

Example: Migration
• Add a boolean flag to the accounts table and remove it again, if you’re backing out of the migration.
  1. class AddSsl < ActiveRecord::Migration
  2. def self.up
  3. add_column :accounts:ssl_enabled:boolean:default => 1
  4. end
  5. def self.down
  6. remove_column :accounts:ssl_enabled
  7. end
  8. end

Example: Migration
• First adds the system_settings table, then creates the very first row in it using the Active Record model that relies on the table.
  1. class AddSystemSettings < ActiveRecord::Migration
  2. def self.up
  3. create_table :system_settings do |t|
  4. t.column :name:string
  5. t.column :label:string
  6. t.column :value:text
  7. end
  8. SystemSetting.create :name => "notice":label => "Use notice?":value => 1
  9. end
  10. def self.down
  11. drop_table :system_settings
  12. end
  13. end
Available Transformations
• create_table(name, options)
• drop_table(name)
• rename_table(old_name, new_name)
• add_column(table_name, column_name, type, options)
• rename_column(table_name, column_name, new_column_name)
• change_column(table_name, column_name, type, options)
• remove_column(table_name, column_name)
• add_index(table_name, column_names, index_type, index_name)
• remove_index(table_name, index_name)

Callbacks
回滾
What is Callback?
• Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic before or after an alteration of the object state.
回滾就是一個生命週期的一個點,可以在發生改變後混滾到該點
• This can be used to make sure that associated and dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes before they‘re validated (by overwriting before_validation).

Lifecycle of an ActiveRecord Object
• (-) save
• (-) valid
• (1) before_validation
• (2) before_validation_on_create
• (-) validate
• (-) validate_on_create
• (3) after_validation
• (4) after_validation_on_create
• (5) before_save
• (6) before_create
• (-) create
• (7) after_create
• (8) after_save

Example: Callbacks in a Model
• The callback before_validation_on_create gets called on create.
  1. class User < ActiveRecord::Base
  2. # Strip everything but alphabets
  3. def before_validation_on_create
  4. self.name = name.gsub(/[^A-Za-z]/, ""if attribute_present?("name")
  5. end
  6. # More code
  7. end

Exception Handling
異常處理
Exception Handling
• Handle RecordNotFound Exception
  1. begin
  2. User.find(2345)
  3. rescue ActiveRecord::RecordNotFound
  4. outs “Not found!”
  5. end


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章