Active Record¶ ↑
Active Record 对象不直接指定其属性,而是从它们所关联的表定义中推断出来。属性及其类型的添加、删除和更改直接在数据库中完成。任何更改都会立即反映在 Active Record 对象中。在大多数常见情况下,将给定的 Active Record 类绑定到特定数据库表会的映射是自动发生的,但也可以为不常见的情况进行覆盖。
有关更多详细信息,请参阅 `table_name` 中的映射规则以及 `files/activerecord/README_rdoc.html` 文件中的完整示例。
创建¶ ↑
Active Record 接受哈希或块形式的构造函数参数。当您从其他地方(如 HTTP 请求)接收数据时,哈希方法特别有用。它工作原理如下:
user = User.new(name: "David", occupation: "Code Artist") user.name # => "David"
您还可以使用块进行初始化。
user = User.new do |u| u.name = "David" u.occupation = "Code Artist" end
当然,您也可以只创建一个空对象,然后在事后指定属性。
user = User.new user.name = "David" user.occupation = "Code Artist"
条件¶ ↑
条件可以指定为字符串、数组或表示 SQL 语句 WHERE 部分的哈希。当条件输入被污染并需要清理时,应使用数组形式。对于不涉及污染数据的语句,可以使用字符串形式。哈希形式的工作方式与数组形式非常相似,但只能进行相等和范围的比较。示例:
class User < ActiveRecord::Base def self.authenticate_unsafely(user_name, password) where("user_name = '#{user_name}' AND password = '#{password}'").first end def self.authenticate_safely(user_name, password) where("user_name = ? AND password = ?", user_name, password).first end def self.authenticate_safely_simply(user_name, password) where(user_name: user_name, password: password).first end end
`authenticate_unsafely` 方法直接将参数插入查询,因此如果 `user_name` 和 `password` 参数直接来自 HTTP 请求,则容易受到 SQL 注入攻击。`authenticate_safely` 和 `authenticate_safely_simply` 都将在将 `user_name` 和 `password` 插入查询之前对其进行清理,这将确保攻击者无法逃避查询并伪造登录(或更糟)。
当条件中使用多个参数时,很难准确地知道第四个或第五个问号代表什么。在这种情况下,您可以改用命名绑定变量。通过将问号替换为符号,并提供一个包含匹配符号键值的哈希来实现。
Company.where( "id = :id AND name = :name AND division = :division AND created_at > :accounting_date", { id: 3, name: "37signals", division: "First", accounting_date: '2005-01-01' } ).first
类似地,没有语句的简单哈希将基于 SQL AND 运算符的相等性生成条件。例如:
Student.where(first_name: "Harvey", status: 1) Student.where(params[:student])
在哈希中使用范围可以使用 SQL BETWEEN 运算符。
Student.where(grade: 9..12)
在哈希中使用数组可以使用 SQL IN 运算符。
Student.where(grade: [9,11,12])
当连接表时,可以使用嵌套哈希或以 'table_name.column_name' 形式编写的键来限定特定条件的表名。例如:
Student.joins(:schools).where(schools: { category: 'public' }) Student.joins(:schools).where('schools.category' => 'public' )
覆盖默认访问器¶ ↑
所有列值都可以通过 Active Record 对象上的基本访问器自动获取,但有时您希望专门化此行为。这可以通过覆盖默认访问器(使用与属性相同的名称)并调用 `super` 来实际更改事物来实现。
class Song < ActiveRecord::Base # Uses an integer of seconds to hold the length of the song def length=(minutes) super(minutes.to_i * 60) end def length super / 60 end end
属性查询方法¶ ↑
除了基本访问器外,查询方法也会在 Active Record 对象上自动可用。查询方法允许您测试属性值是否存在。此外,在处理数值时,查询方法在值为零时将返回 false。
例如,一个具有 `name` 属性的 Active Record User 对象有一个 `name?` 方法,您可以调用它来确定用户是否有名。
user = User.new(name: "David") user.name? # => true anonymous = User.new(name: "") anonymous.name? # => false
查询方法还将尊重对默认访问器的任何覆盖。
class User # Has admin boolean column def admin false end end user.update(admin: true) user.read_attribute(:admin) # => true, gets the column value user[:admin] # => true, also gets the column value user.admin # => false, due to the getter override user.admin? # => false, due to the getter override
在属性类型转换之前访问属性¶ ↑
有时您希望能够读取原始属性数据,而不必先进行由列决定的类型转换。这可以通过使用所有属性都拥有的 `<attribute>_before_type_cast` 访问器来实现。例如,如果您的 Account 模型有一个 `balance` 属性,您可以调用 `account.balance_before_type_cast` 或 `account.id_before_type_cast`。
这在验证情况下特别有用,因为用户可能为整数字段提供一个字符串,而您想在错误消息中显示原始字符串。正常访问属性会将字符串类型转换为 0,这不是您想要的。
动态基于属性的查找器¶ ↑
动态基于属性的查找器是一种被轻微弃用的获取(和/或创建)对象的方法,通过简单查询而不是诉诸 SQL。它们通过将属性名附加到 `find_by_` 来工作,例如 `Person.find_by_user_name`。与其编写 `Person.find_by(user_name: user_name)`,不如使用 `Person.find_by_user_name(user_name)`。
可以在动态查找器末尾添加感叹号(!),以便在未找到记录时引发 `ActiveRecord::RecordNotFound` 错误,例如 `Person.find_by_last_name!`。
还可以通过用“and”分隔来在同一个 `find_by_` 中使用多个属性。
Person.find_by(user_name: user_name, password: password) Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
甚至可以在 relation 和命名范围上调用这些动态查找方法。
Payment.order("created_on").find_by_amount(50)
在文本列中保存数组、哈希和其他不可映射对象¶ ↑
Active Record 可以使用 YAML 在文本列中序列化任何对象。要做到这一点,您必须通过调用类方法 `serialize` 来指定。这使得无需进行任何额外的工作就可以存储数组、哈希和其他不可映射的对象。
class User < ActiveRecord::Base serialize :preferences end user = User.create(preferences: { "background" => "black", "display" => large }) User.find(user.id).preferences # => { "background" => "black", "display" => large }
您还可以指定一个类选项作为第二个参数,如果检索到的序列化对象是继承自不在该层次结构中的类的子类,则会引发异常。
class User < ActiveRecord::Base serialize :preferences, Hash end user = User.create(preferences: %w( one two three )) User.find(user.id).preferences # raises SerializationTypeMismatch
当您指定一个类选项时,该属性的默认值将是该类的新实例。
class User < ActiveRecord::Base serialize :preferences, OpenStruct end user = User.new user.preferences.theme_color = "red"
单表继承¶ ↑
Active Record 允许通过将类名存储在默认命名为“type”的列中来实现继承。有关更多详细信息,请参阅 `ActiveRecord::Inheritance`。
连接到不同模型中的多个数据库¶ ↑
连接通常通过 `ActiveRecord::Base.establish_connection` 创建,并通过 `ActiveRecord::Base.lease_connection` 检索。所有继承自 `ActiveRecord::Base` 的类都将使用此连接。但是您也可以设置特定于类的连接。例如,如果 `Course` 是一个 `ActiveRecord::Base`,但位于不同的数据库中,您只需说 `Course.establish_connection`,`Course` 及其所有子类都将使用此连接。
此功能通过在 `ActiveRecord::Base` 中维护一个由类索引的哈希连接池来实现。如果请求连接,`ActiveRecord::Base.retrieve_connection` 方法将沿着类层次结构向上查找,直到在连接池中找到连接。
异常¶ ↑
-
ActiveRecordError- Active Record 抛出的所有其他错误的通用类和超类。 -
AdapterNotSpecified- `ActiveRecord::Base.establish_connection` 中使用的配置哈希未包含 `:adapter` 键。 -
AdapterNotFound- `ActiveRecord::Base.establish_connection` 中使用的 `:adapter` 键指定了一个不存在的适配器(或现有适配器的拼写错误)。 -
AssociationTypeMismatch- 分配给关联的对象不是在关联定义中指定的类型。 -
AttributeAssignmentError- 在通过 `ActiveRecord::Base#attributes=` 方法进行批量赋值时出错。您可以检查异常对象的 `attribute` 属性来确定哪个属性触发了错误。 -
ConnectionNotEstablished- 未建立连接。在查询之前使用 `ActiveRecord::Base.establish_connection`。 -
MultiparameterAssignmentErrors- 在通过 `ActiveRecord::Base#attributes=` 方法使用批量赋值期间发生的错误集合。此异常的 `errors` 属性包含一个 `AttributeAssignmentError` 对象数组,应检查该数组以确定哪些属性触发了错误。 -
RecordInvalid- 由 `ActiveRecord::Base#save!` 和 `ActiveRecord::Base.create!` 在记录无效时引发。 -
RecordNotFound- 没有记录响应 `ActiveRecord::Base.find` 方法。要么具有给定 ID 的行不存在,要么该行不满足其他限制。一些 `ActiveRecord::Base.find` 调用不会引发此异常来表示未找到任何内容,请检查其文档以获取更多详细信息。 -
SerializationTypeMismatch- 序列化对象不是指定的第二个参数的类。 -
StatementInvalid- 数据库服务器拒绝了 SQL 语句。精确的错误已添加到消息中。
注意:列出的属性是类级别的属性(可从类和实例级别访问)。因此,可以通过 `Base.logger=` 向类分配一个日志记录器,该日志记录器将被当前对象空间中的所有实例使用。
- ActiveModel::API
- ActiveRecord::Core
- ActiveRecord::Persistence
- ActiveRecord::ReadonlyAttributes
- ActiveRecord::ModelSchema
- ActiveRecord::Inheritance
- ActiveRecord::Scoping
- ActiveRecord::Sanitization
- ActiveRecord::AttributeAssignment
- ActiveRecord::Integration
- ActiveRecord::Validations
- ActiveRecord::CounterCache
- ActiveRecord::Attributes
- ActiveRecord::Locking::Optimistic
- ActiveRecord::Locking::Pessimistic
- ActiveRecord::Encryption::EncryptableRecord
- ActiveRecord::AttributeMethods
- ActiveRecord::Callbacks
- ActiveRecord::Timestamp
- ActiveRecord::Associations
- ActiveRecord::SecurePassword
- ActiveRecord::AutosaveAssociation
- ActiveRecord::NestedAttributes
- ActiveRecord::Transactions
- ActiveRecord::NoTouching
- ActiveRecord::Reflection
- ActiveRecord::AttributeMethods::Serialization
- ActiveRecord::Store
- ActiveRecord::SecureToken
- ActiveRecord::TokenFor
- ActiveRecord::SignedId
- ActiveRecord::Suppressor
- ActiveRecord::Marshalling::Methods