Active Record Basics --- Ruby on Rails Guides
Active Record Migrations --- Ruby on Rails Guides
原文链接自取
1.Active Record是什么?
Active Record是MVC模式中M的一部分,是负责展示数据和业务逻辑的一层,可以帮助你创建和使用Ruby对象,这些对象的属性需要持久存储到数据库中。
Active Record 有一些约定好的规则,它在不需要配置的情况下使用这些规则映射models和数据表:Rails 会将你model的类名复数化用来寻找对应的数据表,比如一个类名为Book将会被隐射到数据表books; BookClub的类将被映射到book_clubs.
2.Active Record Models?
创建过Models的人都经常能看见这个,估计也不明白这个具体是啥,只知道它将创建一个Book model,映射到数据库中的books table, 表中的每一栏都可以映射到Book类中的属性。An instance of Book
can represent a row in the books
table.
ruby
class Book < ApplicationRecord
end
官网解答来了
When generating a Rails application, an abstract ApplicationRecord
class will be created in app/models/application_record.rb
. The ApplicationRecord
class inherits from ActiveRecord::Base and it's what turns a regular Ruby class into an Active Record model.
ApplicationRecord
is the base class for all Active Record models in your app. To create a new model, subclass the ApplicationRecord
class.
因为我对此了解也不深入,所以就不翻译了,从原文里可以了解的更多。
3.C reate, R ead, U pdate, and Delete(CRUD)
Active Record automatically creates methods to allow you to read and manipulate data stored in your application's database tables.
Active Record通过抽象出数据库访问细节的高级方法,无缝执行DRUD操作。注意,所有这些方便的方法都会产生针对底层数据库执行的SQL语句。
下面的示例展示了一些 CRUD 方法以及由此产生的 SQL 语句。
3.1 Create
Active Record对象可以通过哈希值,块创建,也可以在创建后手动设置属性。new 方法将返回一个新的,非存在的对象,而create将把这个对象保存到数据库并返回。
例如,给定一个具有title和author属性的Book model,调用create方法将创建一个对象并保存一条新纪录到数据库中。
ruby
book = Book.create(title: "The Lord of the Rings", author: "J.R.R. Tolkien")
# Note that the `id` is assigned as this record is committed to the database.
book.inspect
# => "#<Book id: 106, title: \"The Lord of the Rings\", author: \"J.R.R. Tolkien\", created_at: \"2024-03-04 19:15:58.033967000 +0000\", updated_at: \"2024-03-04 19:15:58.033967000 +0000\">"
ruby
book = Book.new
book.title = "The Hobbit"
book.author = "J.R.R. Tolkien"
# Note that the `id` is not set for this object.
book.inspect
# => "#<Book id: nil, title: \"The Hobbit\", author: \"J.R.R. Tolkien\", created_at: nil, updated_at: nil>"
# The above `book` is not yet saved to the database.
book.save
book.id # => 107
# Now the `book` record is committed to the database and has an `id`.
book.save 和 Book.create 产生的 SQL 语句如下所示:
sql
/* Note that `created_at` and `updated_at` are automatically set. */
INSERT INTO "books" ("title", "author", "created_at", "updated_at") VALUES (?, ?, ?, ?) RETURNING "id" [["title", "Metaprogramming Ruby 2"], ["author", "Paolo Perrotta"], ["created_at", "2024-02-22 20:01:18.469952"], ["updated_at", "2024-02-22 20:01:18.469952"]]
3.2 Read
ruby
# Return a collection with all books.
books = Book.all
# Return a single book.
first_book = Book.first
last_book = Book.last
book = Book.take
对应的SQL:
sql
-- Book.all
SELECT "books".* FROM "books"
-- Book.first
SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ? [["LIMIT", 1]]
-- Book.last
SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT ? [["LIMIT", 1]]
-- Book.take
SELECT "books".* FROM "books" LIMIT ? [["LIMIT", 1]]
这个地方有个需要注意的点,就是find_by和where,他们都可以用来查找特定的图书。find_by返回单条记录,而where返回记录列表!
ruby
# Returns the first book with a given title or `nil` if no book is found.
book = Book.find_by(title: "Metaprogramming Ruby 2")
# Alternative to Book.find_by(id: 42). Will throw an exception if no matching book is found.
book = Book.find(42)
对应的SQL
sql
-- Book.find_by(title: "Metaprogramming Ruby 2")
SELECT "books".* FROM "books" WHERE "books"."title" = ? LIMIT ? [["title", "Metaprogramming Ruby 2"], ["LIMIT", 1]]
-- Book.find(42)
SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 42], ["LIMIT", 1]]
ruby
# Find all books by a given author, sort by created_at in reverse chronological order.
Book.where(author: "Douglas Adams").order(created_at: :desc)
sql
SELECT "books".* FROM "books" WHERE "books"."author" = ? ORDER BY "books"."created_at" DESC [["author", "Douglas Adams"]]
读取查询记录的方法还有很多。Active Record Query Interface --- Ruby on Rails Guides
3.3 Update
检索到 Active Record 对象后,就可以修改其属性并保存到数据库中
ruby
book = Book.find_by(title: "The Lord of the Rings")
book.title = "The Lord of the Rings: The Fellowship of the Ring"
book.save
可以使用hash简写
ruby
book = Book.find_by(title: "The Lord of the Rings")
book.update(title: "The Lord of the Rings: The Fellowship of the Ring")
对应的SQL
sql
/* Note that `updated_at` is automatically set. */
UPDATE "books" SET "title" = ?, "updated_at" = ? WHERE "books"."id" = ? [["title", "The Lord of the Rings: The Fellowship of the Ring"], ["updated_at", "2024-02-22 20:51:13.487064"], ["id", 104]]
如果想批量更新多条记录 without callbacks or validations,可以直接使用update_all
ruby
Book.update_all(status: "already own")
3.4 Delete
同样,检索到Active Record 对象后,也可以删除它,并从数据库中删除。
ruby
book = Book.find_by(title: "The Lord of the Rings")
book.destroy
对应的SQL
sql
DELETE FROM "books" WHERE "books"."id" = ? [["id", 104]]
如果想批量删掉多条数据,可以使用 destroy_by 或 destroy_all 方法,注意使用这个方法蕴含的风险哈!
ruby
# Find and delete all books by Douglas Adams.
Book.destroy_by(author: "Douglas Adams")
# Delete all books.
Book.destroy_all
4.Validations
Active Record允许你在model写入数据库之前验证其状态。有几种方法可以进行不同类型的验证。例如,验证属性值是否为空、是否唯一、是否已存在于数据库中、是否遵循特定格式等等。
save, create and update方法在将model持久化到数据库之前进行验证。当model无效时,这些方法返回false并且不执行数据库操作。所有这些方法都有一个对应的方法(即save!, create! and update!),它们在验证失败时会引发一个 ActiveRecord::RecordInvalid 异常,更加严格。例如:
ruby
class User < ApplicationRecord
validates :name, presence: true
end
ruby
irb> user = User.new
irb> user.save
=> false
irb> user.save!
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
关于验证的更多内容可以看 Active Record Validations --- Ruby on Rails Guides
5. Callbacks
Active Record callbacks允许你附加代码到models生命周期中的某些事件上。This enables you to add behavior to your models by executing code when those events occur, like when you create a new record, update it, destroy it, and so on.。
ruby
class User < ApplicationRecord
after_create :log_new_user
private
def log_new_user
puts "A new user was registered"
end
end
ruby
irb> @user = User.create
A new user was registered
更多可见Active Record Callbacks --- Ruby on Rails Guides
6.Migrations
Rails provides a convenient way to manage changes to a database schema via migrations. Migrations are written in a domain-specific language and stored in files which are executed against any database that Active Record supports.
下面的migration创建了一个名为publications 的新表:
ruby
class CreatePublications < ActiveRecord::Migration[7.2]
def change
create_table :publications do |t|
t.string :title
t.text :description
t.references :publication_type
t.references :publisher, polymorphic: true
t.boolean :single_issue
t.timestamps
end
end
end
Rails 会记录哪些migrations已提交到数据库,并将它们存储在同一数据库中名为 schema_migrations 的neighboring table中。
要运行migration 并创建表格,需要运行 bin/rails db:migrate,要回滚并删除表格,需要运行 bin/rails db:rollback。
更多请看Active Record Migrations --- Ruby on Rails Guides
6.Associations
Active Record associations 允许你定义models之间的关系。Associations 可用于描述one-to-one, one-to-many, 和 many-to-many关系。 比如,"Author has many Books"的关系可以这样定义:
ruby
class Author < ApplicationRecord
has_many :books
end
Author类现在有了为an author添加和删除books的方法,甚至更多。