重学rails: active-record 基础

基本的 active-record 使用
更新于: 2024-10-19 22:48:53

What

Active Record 是MVC中 M 的一部分- 模型 - 是系统中负责表示数据业务逻辑的层。Active Record 可帮助您创建和使用 Ruby 对象,其属性需要持久存储到数据库中。

命名约定

对于由两个或多个单词组成的类名,模型类名将遵循使用 UpperCamelCase 名称的 Ruby 约定。在这种情况下,数据库表名称将采用 snake_case 名称。例如:

  • BookClub是模型类,单数,每个单词的首字母大写。
  • book_clubs是匹配的数据库表,复数形式,用下划线分隔单词。

以下是一些模型类名和对应表名的示例:

型号/类别表/模式

Article

articles

LineItem

line_items

Product

products

Person

people

架构约定

Active Record 也使用数据库表中列名的约定,具体取决于这些列的用途。

  • 主键- 默认情况下,Active Record 将使用一个整数列 id作为表的主键(bigint对于 PostgreSQL、MySQL 和 MariaDB, integer对于 SQLite)。使用Active Record Migrations创建表时,将自动创建此列。
  • 外键- 这些字段应按照以下模式命名 singularized_table_name_id(例如order_idline_item_id)。当您在模型之间创建关联时,Active Record 将查找这些字段。

还有一些可选的列名将为 Active Record 实例添加附加功能:

  • created_at- 首次创建记录时自动设置为当前日期和时间。
  • updated_at- 每当创建或更新记录时自动设置为当前日期和时间。
  • lock_version-向模型添加乐观锁定。
  • type- 指定模型使用单表继承
  • (association_name)_type— 存储多态关联的类型。
  • (table_name)_count- 用于缓存关联上的所属对象的数量。例如,如果Articles 有很多Comments, 表comments_count中的一列articles将缓存每篇文章的现有评论数量。

创建Modal 对应SQL

class Book < ApplicationRecord
end
CREATE TABLE books (
  id int(11) NOT NULL auto_increment,
  title varchar(255),
  author varchar(255),
  PRIMARY KEY  (id)
);

创建 Migrations

bin/rails generate migration CreateBooks title:string author:string
# Note:
# The `id` column, as the primary key, is automatically created by convention.
# Columns `created_at` and `updated_at` are added by `t.timestamps`.

class CreateBooks < ActiveRecord::Migration[8.0]
  def change
    create_table :books do |t|
      t.string :title
      t.string :author

      t.timestamps
    end
  end
end

创建命名空间模型

bin/rails generate model Book::Order
module Book
  def self.table_name_prefix
    "book_"
  end
end

class Book::Order < ApplicationRecord
end

# 查看表名
Book::Order.table_name
# => "book_orders"

自定义 table_name

class Book < ApplicationRecord
  self.table_name = "my_books"
end

自定义 primary_key

class Book < ApplicationRecord
  self.primary_key = "book_id"
end

CURD 之 Create

创建,并存数据库,已经产生ID

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\">"

CURD 之 New

创建,但不存数据库,还没有产生 ID

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`.
/* 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"]]

查询 R

  • all: 所有
  • find/find_by: 查询单个
  • where: 查询多个
# Return a collection with all books.
books = Book.all

# Return a single book.
first_book = Book.first
last_book = Book.last
book = Book.take
# 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)
# Find all books by a given author, sort by created_at in reverse chronological order.
Book.where(author: "Douglas Adams").order(created_at: :desc)

更新 Update

  • 标准写法
  • 简化写法
  • 一次性更新所有的值
book = Book.find_by(title: "The Lord of the Rings")
book.title = "The Lord of the Rings: The Fellowship of the Ring"
book.save
book = Book.find_by(title: "The Lord of the Rings")
book.update(title: "The Lord of the Rings: The Fellowship of the Ring")
Book.update_all(status: "already own")

删除 Destroy

book = Book.find_by(title: "The Lord of the Rings")
book.destroy
# Find and delete all books by Douglas Adams.
Book.destroy_by(author: "Douglas Adams")

# Delete all books.
Book.destroy_all

验证 Validation

  • 验证存在
  • 错误信息
class User < ApplicationRecord
  validates :name, presence: true
end
user = User.create
user.errors.full_messages

回调 Callback(Event)

class User < ApplicationRecord
  after_create :log_new_user

  private
    def log_new_user
      puts "A new user was registered"
    end
end
@user = User.create
# A new user was registered

Relation

  • 1 对多
class Author < ApplicationRecord
  has_many :books
end