Rails Model

https://guides.rubyonrails.org/

https://api.rubyonrails.org/

第一次写于 : 2020年3月22日

忙碌了一段时间,这几天根据官方文档和API手册,学习了一些Rails中对数据库操作的内容;
也就是Active Record;

文章中大部分内容就是对文档的翻译和抽取; 同时,也加入了一些个人的理解;
翻译过程,有些内容懒得翻译了;

好的框架都是相似的,不好的框架各不相同;

学习过spring,JPA 等框架;
发现除了写法上有差异,但是总体上类似;

ORM框架啊,都是对数据库操作的封装;
这里,就不得不提, 学好SQL和数据库原理对使用ORM框架是非常有帮助的;
当然,这两者也是相辅相成的;

知道原理后,ORM就是对这些操作的封装.使用起来会更加得心应手;

Active Record 基础

命名约定

命名约定

模型Class 大驼峰单数
rails会自动生成 复数的名称的table

模式约定

模型Class 大驼峰单数

创建 Active Record 模型

默认会添加三个字段

  • id
  • created_at
  • updated_at
rails g model User username:string

命令输入完成后,会在 db/migrate 目录下生成一个迁移文件
完善文件后 执行迁移命令

rails db:migrate

之后,我们就可以在 db/schema.rb 文件中看到我们声明的model

记住: 这个文件只能看,不要手动修改;

覆盖命名约定:self.table_name

取消默认命名;使用自定义的命名

class Product < ApplicationRecordself.table_name = "my_products"
end

CRUD

在官网上有详细的介绍

https://guides.rubyonrails.org/active_record_basics.html

  • 创建
user = User.create(name: "David", occupation: "Code Artist")
# 只有当执行save方法时; 才会把数据保存到数据库中
user = User.new
user.name = "David"
user.occupation = "Code Artist"
user.save
  • 读取
user = User.first
user = User.find_by_id(1)
  • 更新
user = User.first
user.update(username: "hello")
#
user.name = 'Dave'
user.saveUser.update_all "max_login_attempts = 3, must_change_password = 'true'"
  • 删除
user = User.find_by(name: 'David')
user.destroy# find and delete all users named David
User.destroy_by(name: 'David')# delete all users
User.destroy_all

事务

Transactions

事务的开启

尽管,事务是被每一个Active Record类调用的;
但是,由于一个事务属于一个数据库连接,而非一个class;
因此,在一个class中,写不用的model调用也是可以的;

另外 savedestroy 方法,自动被事务包裹

我们传入一个 block ; 在这个block中的操作都会被事务包裹;

分布式事务, 不在Active Record 支持范围;

Account.transaction dobalance.save!account.save!
endbalance.transaction dobalance.save!account.save!
end

事务中的异常处理

记住,如果一个事务block中抛出的异常,会在触发ROLLBACK后传播到上级;
注意要捕获这些问题;

我们不要在事务的block中 捕获ActiveRecord::StatementInvalid ;
如果捕获了,可能会导致整个事务的block被废弃;

# Suppose that we have a Number model with a unique column called 'i'.
Number.transaction doNumber.create(i: 0)begin# This will raise a unique constraint error...Number.create(i: 0)rescue ActiveRecord::StatementInvalid# ...which we ignore.end# On PostgreSQL, the transaction is now unusable. The following# statement will cause a PostgreSQL error, even though the unique# constraint is no longer violated:Number.create(i: 1)# => "PG::Error: ERROR:  current transaction is aborted, commands#     ignored until end of transaction block"
end

内置事务

内置事务只有MS-SQL支持,Active Record 只是尽可能的模拟内置事务;
下面操作的结果可能会令你大吃一惊;

User.transaction doUser.create(username: 'Kotori')User.transaction doUser.create(username: 'Nemu')raise ActiveRecord::Rollbackend
end

这样,会创建两个对象 Kotori 和 Nemu;
尽管,抛出了异常,但是并没有让事务回滚;

在事务block中发生的异常,父级block看不到;导致了无法回滚;

下面, User.transaction(requires_new: true) 设置需要新的事务块
可以正常回滚;
但是,实际上很多数据库是不支持内置事务的,这只是模拟;

User.transaction doUser.create(username: 'Kotori')User.transaction(requires_new: true) doUser.create(username: 'Nemu')raise ActiveRecord::Rollbackend
end

Active Record 迁移

命令

If the migration name is of the form “AddColumnToTable” or “RemoveColumnFromTable” and
is followed by a list of column names and types then a migration containing the appropriate
add_column and remove_column statements will be created.

创建独立的迁移

rails generate migration AddPartNumberToProducts

生成的迁移文件会有一个timestamp 前缀;
每次迁移都会在数据库中生成一条记录;
防止数据操作不一致;导致数据库修改错乱;

执行迁移命令

rails db:migrate

模型生成器:命令

rails g model User

创建数据表

一般都是通过创建model 来生成迁移文件

class CreateUsers < ActiveRecord::Migration[6.0]def changecreate_table :users do |t|t.string :usernamet.string :passwordt.numeric :gendert.string :avatar_urlt.string :emailt.timestampsendend
end

修改字段

添加字段

rails generate migration AddPartNumberToProducts part_number:string

change_column command is irreversible. 改变column是不可逆的

class AddTestToUsers < ActiveRecord::Migration[6.0]def changeadd_column :users, :test, :stringremove_column :users,:test# change_column :users,:gender,:textadd_index :users,:usernamechange_column_null :products, :name, falsechange_column_default :products, :approved, from: true, to: falseend
end

字段修饰符(重要)

column-modifiers

字段修改符 可以用在修改或者创建column时

  • limit Sets the maximum size of the string/text/binary/integer fields.
  • precision Defines the precision for the decimal fields, representing the total number of digits in the number.
  • scale Defines the scale for the decimal fields, representing the number of digits after the decimal point.
  • polymorphic Adds a type column for belongs_to associations.
  • null Allows or disallows NULL values in the column.
  • default Allows to set a default value on the column. Note that if you are using a dynamic value (such as a date), the default will only be calculated the first time (i.e. on the date the migration is applied).
  • comment Adds a comment for the column.
# change_column(:users, :password, :string, {:limit=>30, :default=>"123456", :comment=>"加入默认密码"})
change_column :users, :password, :string, limit: 30, default: '123456'

execute

执行任意sql

Product.connection.execute("UPDATE products SET price = 'free' WHERE 1=1")

change 方法

change 方法中; 可以使用之前所用的add remove字段等;

up 和 down 方法

这是一个过时的方法; 但也可以使用;

up 和 down 方法是成对出现的;

  • up 表示将要修改的内容
  • down 表示要回退的内容 rollback

例如: 在up中我给username 加入了索引; 那么在 down中就要定义 删除username的索引;

运行指定迁移

迁移

VERSION=时间戳

rails db:migrate VERSION=20080906120000

如果VERSION版本比现在的新
那么它会执行 change 或 up 方法;

如果发现执行的代码错误了
可以使用rollback 回滚

rails db:rollback

在不同环境中运行迁移

rails db:migrate RAILS_ENV=test

Active Record 查询

方法名中 带有 ! 标明可能会报异常
带有 ? 返回 true/false

The find method will raise an ActiveRecord::RecordNotFound exception if no matching record is found.

查询方法中返回一个集合 (例如 where , group ) 是 ActiveRecord::Relation 实例对象
查询方法中返回一个对象 (例如 find , first ) 是 model 的一个单独实例对象

单表查询

active_record_querying

简单查询

# find 如果找不到会报异常
# SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1
user = User.find(1)
user = User.find([1,2])
# find_by_id
user = User.find_by_id(1)
# take 按照数据库隐式排序提取前两条
user = User.take(2)
# first 主键asc 第一条
# SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
user = User.first
user = User.first(3)
# 返回第一条符合的数据
user = User.find_by(username: 'ju')
# 默认0 , 1000
User.find_each(start: 2000, batch_size: 5000) do |user|NewsMailer.weekly(user).deliver_now
end

数据存在不存在

Client.exists?(1)
Client.exists?(id: [1,2,3])
Client.exists?(name: ['John', 'Sergei'])
Client.where(first_name: 'Ryan').exists?

count

Client.count
# SELECT COUNT(*) FROM clients
Client.where(first_name: 'Ryan', orders: { status: 'received' }).count

where

不要使用参数拼接
这样会有sql注入

Never ever put your arguments directly inside the conditions string.

# where
# 下面这么查询是不安全的
User.where("id = " + id)
# 使用 ? 占位符
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
# 加入参数
users = User.where(name: 'David', occupation: 'Code Artist').order(created_at: :desc)

占位符

# 问号占位符(?)
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
# Placeholder Conditions
Client.where("created_at >= :start_date AND created_at <= :end_date",{start_date: params[:start_date], end_date: params[:end_date]})
# hash条件
Client.where(id:1)

覆盖:unscope(了解)

用的比较少; 表示去掉一部分执行

# SELECT "articles".* FROM "articles" WHERE trashed = 0
Article.where(id: 10, trashed: false).unscope(where: :id)

only 表示只执行

# SELECT * FROM articles WHERE id > 10 ORDER BY id DESC
Article.where('id > 10').limit(20).order('id desc').only(:order, :where)

select

默认查询全部字段;
也可以显式地指出要查询的内容

Client.select(:viewable_by, :locked)
# OR
Client.select("viewable_by, locked")# distinct
Client.select(:name).distinct
# limit offset
Client.limit(5).offset(30)
# group 分组
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
# having 条件
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)").having("sum(price) > ?", 100)
# includes

批量查询

  • each 把数据都放到内存中; 当大数据量时,不应该使用这种方法;
User.all.each do |ele|# do something
end

下面的两种; 是内存友好型的;

  • find_each

分批读取 ele是一条数据
可以指定batch_size,start,finish

User.find_each do |ele|endUser.find_each(batch_size: 5000) do |user|NewsMailer.weekly(user).deliver_now
end
  • find_in_batches

分批读取 arr是数组

User.find_in_batches do |arr|end

排序:order 多字段排序

默认 asc

Client.order(orders_count: :asc, created_at: :desc)
# OR
Client.order(:orders_count, created_at: :desc)
# OR
Client.order("orders_count ASC, created_at DESC")
# OR
Client.order("orders_count ASC", "created_at DESC")

NOT

Client.where.not(locked: true)

OR

Client.where(locked: true).or(Client.where(orders_count: [1,3,5]))

作用域 (重要)

scopes

scope

scope 可以把常用的查询语句封装起来;
可以model或相关联的对象调用;

注意: scope 返回的都是 ActiveRecord::Relation 对象; 可以使用方法链一直点点点;
但是,普通的方法,如果返回的是false 等可能会造成NoMethodError异常!

-> 表示 lambda rocket

定义

class Article < ApplicationRecordscope :published,               -> { where(published: true) }scope :published_and_commented, -> { published.where("comments_count > 0") }# 带有参数和判断条件scope :created_before, ->(time) { where("created_at < ?", time) if time.present? }
end
Article.published # => [published articles]
Article.created_before Date.now
category = Category.first
category.articles.published # => [published articles belonging to this category]

注意:

class Article < ApplicationRecorddef self.created_before(time)where("created_at < ?", time) if time.present?end
end

看着是不是很像scope 但是有一个很不一样的点;
scope 当返回 nil 时, 也会被处理成 ActiveRecord::Relation
防止调用时出现NoMethodError

default scope

如果想让每一个请求默认加上一个条件;
那么可以在 default_scope 中定义

class Client < ApplicationRecorddefault_scope { where("removed_at IS NULL") }
end

在执行update操作时,默认的scope不会起作用

The default_scope is also applied while creating/building a record when the scope
arguments are given as a Hash. It is not applied while updating a record. E.g.:

unscoped

当然; 有默认的查询条件了;
同时,也会有 不想带着默认查询条件的情况;
unscoped 就是把默认条件去掉

注意: 要和 unscope 区分;

class Client < ApplicationRecorddefault_scope { where(active: true) }
endClient.new          # => #<Client id: nil, active: true>
Client.unscoped.new # => #<Client id: nil, active: nil>

sql查询:

find_by_sql

对于简单的查询,使用model 可以大大地提高我们的效率;
减少重复;

但是,对于复杂的查询,多表联合等;
虽然,使用model也可以做到;

但是,没有SQL语句直接和容易理解;

在Rails 中也提供了接口; 让我们直接使用sql

Client.find_by_sql("SELECT * FROM clientsINNER JOIN orders ON clients.id = orders.client_idORDER BY clients.created_at desc")

find_by_sql 会返回一个 数组
注意: 只有一条数据,也会返回一个数组

pluck

注意 pluck 查询返回的是ruby数组;
数组中的元素也是普通的对象; 并不是ActiveRecord 对象
它适用于大数据量的查询;

class Client < ApplicationRecorddef name"I am #{super}"end
endClient.select(:name).map &:name
# => ["I am David", "I am Jeremy", "I am Jose"]Client.pluck(:name)
# => ["David", "Jeremy", "Jose"]# pluck 并不返回ActiveRecord
Client.pluck(:name).limit(1)
# => NoMethodError: undefined method `limit' for #<Array:0x007ff34d3ad6d8>Client.limit(1).pluck(:name)
# => ["David"]

Dynamic Finders

通过方法名来自定义查询;
用的不多;

Client.find_by_first_name_and_locked("Ryan", true)

Enum

枚举 在一些场景还是挺方便的;
尤其是定义只有几个值的小map

class Book < ApplicationRecordenum availability: [:available, :unavailable]
end

而且rails 还帮我们生成了定义enum的scope

# Both examples below query just available books.
Book.available
# or
Book.where(availability: :available)book = Book.new(availability: :available)
book.available?   # => true
book.unavailable! # => true
book.available?   # => false

Method Chaining

在上面的文章中;
我们可以看到,链式方法的调用;
我们可以不断地点点点,来加上条件,join table;
但是,需要在最后返回一个单独的对象;
否则,无法使用链式调用,并且会报异常

retrieving-a-single-object

Null Relation


# The visible_articles method below is expected to return a Relation.
@articles = current_user.visible_articles.where(name: params[:name])def visible_articlescase rolewhen 'Country Manager'Article.where(country: country)when 'Reviewer'Article.publishedwhen 'Bad User'Article.none # => returning [] or nil breaks the caller code in this caseend
end

多表关联

之前,我们看到的都是单表的查询与处理;
那么,ORM 肯定涉及到多表的关联关系;

下面我们集中精力看一下多表是怎么在Active Record中操作的

Rails中有6种关联关系

association_basics.html

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

一对一 一对多 多对一

belongs_to associations must use the singular term.
If you used the pluralized form in the above example for
the author association in the Book model and tried to create the
instance by Book.create(authors: @author), you would be told that
there was an “uninitialized constant Book::Authors”.
This is because Rails automatically infers the class name from the association name.
If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too.

belongs_to

举个例子: 假设一本书 (Book)有且仅有一个作者(Author)

Book belongs_to Author

那么反过来,对吗?

Author has_one Book

其实是不对的,因为作者可能有两本书;

那么 has_one 可以用在什么地方呢?

class CreateBooks < ActiveRecord::Migration[5.0]def changecreate_table :authors do |t|t.string :namet.timestampsendcreate_table :books do |t|t.belongs_to :authort.datetime :published_att.timestampsendend
end

has_one

has_one 同样是创建 一对一关系的;
但是在语义上有所不同;

我们也可以说

Book has_one Author

但是,我们不会这么做;
因为,两者之间具有主次之分;

以 Book belongs_to Author

has_one 在创建表的时候,并不会创建实际的字段去关联
belongs_to 则会创建一个字段去关联 例如 author_id

has_many 表示一对多的关系;

一个作者可能有0 本书 也有可能有N本书;
注意books ; 要使用复数

那么就可以有

Author has_many Books

class Author < ApplicationRecordhas_many :books
end
class CreateAuthors < ActiveRecord::Migration[5.0]def changecreate_table :authors do |t|t.string :namet.timestampsendcreate_table :books do |t|t.belongs_to :authort.datetime :published_att.timestampsendend
end

Supplier has_one Account
Account has_one Account_history

那么肯定也有

Supplier has_one Account_history

我们可以通过through: :account 来标明;
之后,直接获取

class Supplier < ApplicationRecordhas_one :accounthas_one :account_history, through: :account
endclass Account < ApplicationRecordbelongs_to :supplierhas_one :account_history
endclass AccountHistory < ApplicationRecordbelongs_to :account
end

多对多

has_many :through 经常用于创建多对多的关系;

假设: 病人预约去看病

一个病人通过预约找一个医生去看病;

一个病人可能去找到多个医生看病;
同时,一个医生也会给多个病人看病;

但是,在一次预约看病中;
一个医生只给一个病人看病;

那么就需要使用 has_many :through
:through 后面加的是 中间表, 也就是 预约表

class Physician < ApplicationRecordhas_many :appointmentshas_many :patients, through: :appointments
endclass Appointment < ApplicationRecordbelongs_to :physicianbelongs_to :patient
endclass Patient < ApplicationRecordhas_many :appointmentshas_many :physicians, through: :appointments
end

对应的迁移文件

class CreateAppointments < ActiveRecord::Migration[5.0]def changecreate_table :physicians do |t|t.string :namet.timestampsendcreate_table :patients do |t|t.string :namet.timestampsendcreate_table :appointments do |t|t.belongs_to :physiciant.belongs_to :patientt.datetime :appointment_datet.timestampsendend
end

through: 还有一个方便的功能
就是可以直接获取到has_many 对象的 has_many

加入 Document has_many Sections
Section has_many Paragraphs
通过 has_many :paragraphs, through: :sections 就可以直接
取到 paragraphs

class Document < ApplicationRecordhas_many :sectionshas_many :paragraphs, through: :sections
endclass Section < ApplicationRecordbelongs_to :documenthas_many :paragraphs
endclass Paragraph < ApplicationRecordbelongs_to :section
end
@document.paragraphs

上述情况是建立了一个中间的 model ; 我们可以自定义一些字段处理;

我们也可以使用 Active Record提供的简单的关系

has_and_belongs_to_many 使用这个关系;
Active Record 会帮我们创建一个只有两个字段是中间表;
我们不需要自己创建一个中间的model;

虽然方便了,却也缺少了自定义的字段的功能;

class Assembly < ApplicationRecordhas_and_belongs_to_many :parts
endclass Part < ApplicationRecordhas_and_belongs_to_many :assemblies
end
class CreateAssembliesAndParts < ActiveRecord::Migration[5.0]def changecreate_table :assemblies do |t|t.string :namet.timestampsendcreate_table :parts do |t|t.string :part_numbert.timestampsendcreate_table :assemblies_parts, id: false do |t|t.belongs_to :assemblyt.belongs_to :partendend
end

多表查询

Person.select('people.id, people.name, comments.text').joins(:comments).where('comments.created_at > ?', 1.week.ago)
SELECT people.id, people.name, comments.text
FROM people
INNER JOIN commentsON comments.person_id = people.id
WHERE comments.created_at > '2015-01-01'

N+1问题:includes

eager-loading-associations

饥饿式加载 (eager-loading)关联关系的原因,会造成 N+1 问题;

这个问题是框架为了延迟加载所致;
在需要的时候采取真正地去数据库中查找数据;

一般情况下,这样做会给我带来好处,等我们真正操作完,采取执行数据库层面的操作;

但是,万物有好有坏;

这也给我们带来了著名的 N+1 问题:

clients = Client.limit(10)clients.each do |client|puts client.address.postcode
end

我们看上面的代码, 它会执行多少条SQL 语句呢?

因为 eager-loading 的原因, 它会执行 11 条
先查询前10条, 这是一条SQL;
然后,在每一次each, client.address.postcode 都再执行一条SQL

我们可以看到,这是一个明显的性能浪费;
我们可以通过一次查询到关联的数据,不就可以了吗?
为啥还要傻乎乎地查询那么多次呢!!

所以,Active Record 为我们提供了 includes 解决这个问题;

clients = Client.includes(:address).limit(10)clients.each do |client|puts client.address.postcode
end
SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addressesWHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))

同时呢:

如果我们经常性地要读取 二级关联的数据;
我们也可以指定 beloings_to 的回调来每次都执行 includes

There’s no need to use includes for immediate associations - that is,
if you have Book belongs_to :author, then the author is eager-loaded automatically when it’s needed.

原来的

class Chapter < ApplicationRecordbelongs_to :book
endclass Book < ApplicationRecordbelongs_to :authorhas_many :chapters
endclass Author < ApplicationRecordhas_many :books
end

加上 includes

class Chapter < ApplicationRecordbelongs_to :book, -> { includes :author }
endclass Book < ApplicationRecordbelongs_to :authorhas_many :chapters
endclass Author < ApplicationRecordhas_many :books
end

Active Record 回调

回调可理解为Hook

目的就是对某一个状态下,进行统一的操作;

例如,在save前,save后之类的;
很多框架都提供类似的hook;

As you start registering new callbacks for your models, they will be queued for execution. This queue will include all your model’s validations, the registered callbacks, and the database operation to be executed.
The whole callback chain is wrapped in a transaction.
If any callback raises an exception, the execution chain gets halted and a ROLLBACK is issued.
To intentionally stop a chain use:

注册回调

The :on option specifies when a callback will be fired. If you don’t supply the :on option the callback will fire for every action.

class User < ApplicationRecord
# on 指定操作类型before_validation :normalize_name, on: :create# :on takes an array as wellafter_validation :set_location, on: [ :create, :update ]privatedef normalize_nameself.name = name.downcase.titleizeenddef set_locationself.location = LocationService.query(self)end
end

可用的回调

available-callbacks

总的来说;

对 CRUD , 对象的初始化, 事务 等各个地方都留有了 HOOK;

触发回调方法

running-callbacks

跳过回调方法

skipping-callbacks

关联回调

relational-callbacks

class User < ApplicationRecordhas_many :articles, dependent: :destroy
endclass Article < ApplicationRecordafter_destroy :log_destroy_actiondef log_destroy_actionputs 'Article destroyed'end
end

条件回调

默认我们加入的回调,都会在每一个hook处执行;
但是,总有例外,是我们不想让它触发的;

conditional-callbacks

class Comment < ApplicationRecordafter_create :send_email_to_author,if: [Proc.new { |c| c.user.allow_send_email? }, :author_wants_emails?],unless: Proc.new { |c| c.article.ignore_comments? }
end

事务回调

There are two additional callbacks that are triggered by the completion of a database
transaction: after_commit and after_rollback

When a transaction completes, the after_commit or after_rollback callbacks are
called for all models created, updated, or destroyed within that transaction.

However, if an exception is raised within one of these callbacks,
the exception will bubble up and any remaining after_commit or after_rollback methods
will not be executed. As such, if your callback code could raise an exception,
you’ll need to rescue it and handle it within the callback in order to allow other callbacks to run.

Using both after_create_commit and after_update_commit in
the same model will only allow the last callback defined to take effect, and will override all others
There is also an alias for using the after_commit callback for both create and update together:

save 是 create update的别名回调
就是说 在create,update时,都会执行save的回调

Rails Model相关推荐

  1. rails 添加外键_如何在Rails后端中添加功能强大的搜索引擎

    rails 添加外键 by Domenico Angilletta 通过多梅尼科·安吉列塔(Domenico Angilletta) In my experience as a Ruby on Rai ...

  2. rails rake和示例

    一篇看到的讲解得不错的文章 http://blog.csdn.net/clskkk2222/article/details/6735365 这里还有一些例子: Rake Documentation  ...

  3. Rails Rake指南

    这是Rails Envy网站的一篇Rake指南,你可以在这里找到原文. 作为RoR开发者,你对Rake一定不会陌生,你可能用它来完成你的单元测试,也可能是迁移数据库,但是你真正理解这些Rake任务到底 ...

  4. Rails Rake 指南

    这是Rails Envy网站的一篇Rake指南,你可以在这里找到原文. 作为RoR开发者,你对Rake一定不会陌生,你可能用它来完成你的单元测试,也可能是迁移数据库,但是你真正理解这些Rake任务到底 ...

  5. php json 参数转译,php json中文被转义

    php 5.4 json_encode($str, JSON_UNESCAPED_UNICODE); 5.4版本以下 方法一 function encode_json($str){ $code = j ...

  6. rails 3 中 app/model 目录下添加继承

    很多时候我们都需要用目录结构来让我们的源代码文件分组管理,这样方便快速找到需要的文件加以维护, rails/app/model 下大量的model文件也需要分类管理,将继承自同意model的文件放在一 ...

  7. Rails Migration Data Model栏位修改及数据类型介绍

    测试版本Ruby:2.3.1   Rails:5.0.1 一.增加栏位 给devise默认的用户新增增加username字段 $ rails generate migration add_userna ...

  8. rails小重构:将图片加入产品Model

    原先的产品product模式中存放的是图片的url,必须手动将图片存入指定目录中.现在略作改动,在数据库中新建一个pictures表,其设定如下: class CreatePictures < ...

  9. 诗歌rails之如何写一个简单的Rails Plugin

    生成plugin骨架代码: Ruby代码 ruby script\generate plugin MyPlugin ruby script\generate plugin MyPlugin 功能需求: ...

最新文章

  1. 解决python3 UnicodeEncodeError: 'gbk' codec can't encode character '\xXX' in position XX
  2. 蓝桥杯练习系统算法训练习题加答案java版本
  3. 数据结构——树、二叉树、森林、哈夫曼树、字符串模式匹配
  4. php比较float大小,PHP中两个float(浮点数)比较实例分析
  5. 如何将图片序列化_如何将图片文字转化为Word文档?
  6. C语言之局部变量全局变量变量存储方式
  7. mysql 存储过程 用户变量值_mysql:用户变量、系统变量、局部变量(存储过程中的)...
  8. 前端多人开发统一代码格式化工具
  9. widnows下lua开发环境luadist LuaRocks搭建
  10. 对话状态跟踪学习笔记
  11. NOIP模拟赛 czy的后宫5
  12. java 拖拉机_Java——io流
  13. 该怎么标注建筑图纸后进行保存?
  14. 网站制作的流程是什么?网站制作的流程包括哪些步骤?
  15. 一场先进技术与先锋企业碰撞的知识盛宴!弘玑Cyclone『超级自动化的数字内生力量』CXO私享会成功举办
  16. 【Java并发】Java并发编程-01
  17. 【安卓】腾讯Bugly之应用升级热更新-热更新
  18. 算法12---约瑟夫环问题
  19. 麒麟kylin3安装字体
  20. 怀念曾经的sygate firewall

热门文章

  1. java微信小程序太阳码中间logo变成成想要的图片
  2. 【创建和使用类】创建一个名为Restaurant的类,其方法__init__()设置两个属性:
  3. 小程序使用图表(wxcharts)的注意事项
  4. [源码和文档分享]基于Cocos2d-x实现的畜不及防鬼畜音乐节奏游戏
  5. 基于cw32f030c8t6的多功能语音播报提醒装置装置
  6. 运用计算机表演的节目,聆听计算机表演赛背后的故事
  7. Java中Iterator用法
  8. python项目开发常用的目录结构
  9. 适合编程初学者的开源项目:小游戏2048(iOS-SwiftUI版)
  10. css如何设置高亮显示,Javascript实现CSS代码高亮显示