基本的数据检索 |
主键(key)搜索 |
Class.find(keys)
返回主键所对应的数据(一对一)
|
指定键搜索 |
Class.find_by(key, value [,...])
搜索指定的键对应的值
可以指定多个键来追加限制
返回找到的第一个 |
搜索不存在则创建 |
Class.find_or_create_by(同上) |
|
|
|
|
复杂条件下的数据检索 |
设定基本条件式 |
Class.where(exp)
● joins/includes等关联搜索的参数写法
where(关联表格名: {关联处的搜索条件} )
cars = cars.includes(:equipment_spec).where(equipment_specs: { power_window: true })
返回找到的全部(非数组?)
exp |
条件式
哈希表形式 |
哈希表多种形式 |
多个键 |
a: v1, b: v2,
... |
键内范围 |
a: v1..v2
或者a: (v1..v2) |
键内指定多个元素 |
a: [v1, v2, v3, ...] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
用占位符生成条件式 |
Class.where(exp [, value, ...])
占位符: ?或者符号(symbol) :sample
注意: 一定要用占位符,别把输入的字符直接展开进去。SQL可能会爆炸的233
不等于是not, 只用于不是nil
http://railsdoc.com/references/where
例 |
'israre = ? AND def >= ?', false,
1000 |
|
'israre = :sample1 AND def >= :sample2', sample1: false,
sample2: 1000 |
|
Page.where("title not ?", nil) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
where的否定 |
Class.where.not(...)
参数和where一样 |
or |
Class.where(...).or(Class.where(...))
ModelTest.where('ap <= ?',
1000).or(ModelTest.where('def > :def', :def => 4000)) |
排序 |
Class.where(...).order(sort)
参数 |
sort |
排序式
例 :test => :asc
test:
:asc
默认 :asc, 可省略 |
格式 |
属性: 顺序 |
:asc |
升序 |
:desc |
降序 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
重排 |
Class.where(...).order(sort).reorder(sort)
写法和order一样
作用是覆盖前面的order
如果只是想清空前面的order,指定nil |
指定读取的列 |
Class.where(...).select(cols)
默认获取所有的列, 用这个方法可以指定具体要获得的列
cols |
指定的列
:hp, :mp,.... |
select中可以使用SQL函数 |
设置列名称
AS
|
呼出列
|
select中使用SQL函数 |
例: Book.select('AVG(sample) AS avg_sample')
用AS设定名称 |
|
|
|
|
|
去除重复 |
Class.where(...).distinct(flag)
Class.select(...).distinct(flag)
flag |
true 去除重复
false 保留重复
默认true |
|
|
|
|
|
|
|
|
|
获取特定范围 |
limit/offset
和order一起用才有现实意义
limit(rows)
offset(off)
rows |
最多获取的行数 |
off |
开始获取的位置(从0开始) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ModelTest.where('hp >= ? AND mp >= ? AND ad >= ?', 1000,
200, 1500).offset(1).limit(1) |
获取开头/结尾数据 |
Class.first
Class.last
(也可以用limit(0))
不能惰性读取,必须放在方法链最后 |
分组 |
Class.where(...).group(key)
可以指定多个
:a, :b, :c, ... |
进一步提取信息 |
Class. group (key).have(exp)
exp写法参照p206
# TODO:
@having = ModelTest.all.group(:israre).having('hp
>= ?', 0)\ |
select中使用SQL函数 |
例: Book.select('AVG(sample) AS
avg_sample') 用AS设定名称 |
去除条件 |
Class.where(...).select(...)unscope(...).unscope(...)
注意:unscoped是删除之前的所以条件
例
ModelTest.where('def <= :def AND israre = :israre', :def =>
2000, :israre => false).select(:mp,
:mdf).unscope(:select).unscope(where:) |
注意:
如果where里面用最简单的哈希定义,则unscope可以直接删除where的哈希值 |
ModelTest.where(israre: false).unscope(where:
:israre) |
允许的参数 :where, :select, :group, :order, :lock,
:limit, :offset, :joins, :includes, :from, :readonly, :having |
|
|
返回空对象 |
Class.none
Class.where(...)....none
注意: null是空,Class.none这类是空对象(NullObject),可以呼出each等而不出错 |
|
|
|
|
|
|
|
|
|
|
|
|
获取数据的其他方法 |
以数组形式取出列 |
Class.where(...).pluck(column [,...])
例:ModelTest.all.pluck(:israre, :mp) |
确认指定的数据是否存在 |
Class.where(...).exists? |
自定义模型搜索方法 |
命名空间
(Named Scope) |
scope :name, ->{ ... }
scope :rare, -> { where('israre = :israre',
israre: true) }
位置: /app/models/...
调用: sample = Class.where(...).scope-name |
设置默认方法 |
default_scope { ... }
位置: /app/models/...
例: default_scope { order_with_hp }
scope :order_with_hp, ->{
order(:hp) } |
计算结果类 |
获取结果的行数(数量) |
Class.where(...).count
Class.where(...).size
Class.where(...).length
推荐用size,基本没有错 |
计算类 |
平均值 |
average(col) |
最大值 |
minimum(col) |
最小值 |
maximum(col) |
合计值 |
sum(col) |
|
|
一般和group连用 |
ModelTest.all.group(:israre).average(:hp) |
注意 |
返回的是哈希表{group的值: 统计值 [, ...]} |
|
|
|
|
|
|
|
直接使用SQL命令 |
一般都用query method, 尽量不要直接用SQL命令
find_by_sql(sql)
sql |
'....', val1 [, val2 ...] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
记录(record)的登陆,更新,删除 |
基础 |
新建 |
Class.new/build
Class.new(...) Class.build(...)
哈希表形式指定 {:hp => 54321, :mp => 12345,
israre: false}
@new = ModelTest.new({:hp => 54321, :mp =>
12345, israre: false})
|
新建+保存 |
Class.create |
登陆(保存) |
Class#save
返回true/false
注: @sample.save!失败返回例外(用于transaction)
例: @sample.save |
更新 |
@sample.update(...)
返回true/false
哈希表形式指定 {:hp => 54321, :mp => 12345,
israre: false}
用于已经存在的记录(record) |
删除 |
@sample.delete
delete(keys) 单纯删除(直接执行SQL, 不经过Active Recode)
destroy(keys) 先选择后删除,
新手还没理解delete的时候全用destroy就行
例子: sample.delete
Class.delete(id)
注: 用对象呼出时候不用指定id |
进一步的操作 |
全部更新 |
Class.where(...).update_all(updates)
返回改动的行数 |
删除 |
delete(keys) |
单纯删除(并返回被删的)
Member.first.delete
Member Load (0.3ms) SELECT `members`.* FROM `members` ORDER BY `members`.`id` ASC LIMIT 1
SQL (0.6ms) DELETE FROM `members` WHERE `members`.`id` = 207
|
destroy(keys) |
先选择后删除(并返回被删的)
rails相关处理必须用这个才有(transaction, callback)
Member.first.destroy
Member Load (0.4ms) SELECT `members`.* FROM `members` ORDER BY `members`.`id` ASC LIMIT 1
(0.2ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 206
(0.4ms) COMMIT
|
例子: sample.delete
Class.delete(id)
注: 用对象呼出时候不用指定id
|
全部删除 |
delete_all |
直接一次性删除
Member.delete_all
SQL (0.2ms) DELETE FROM `members`
|
destroy_all |
先选择然后一个一个删除(并return 被删除的)
Member.destroy_all
Member Load (0.5ms) SELECT `members`.* FROM `members`
(0.2ms) BEGIN
SQL (0.2ms) DELETE FROM `members` WHERE `members`.`id` = 101
(1.3ms) COMMIT
(0.1ms) BEGIN
SQL (0.2ms) DELETE FROM `members` WHERE `members`.`id` = 102
(0.4ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 103
(0.4ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 104
(0.4ms) COMMIT
(0.2ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 105
(0.4ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 106
(0.4ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) DELETE FROM `members` WHERE `members`.`id` = 107
|
|
transaction
事务 |
def transaction
Class.transaction do
....
raise ...
....
raise ...
...
end
rescue => e
...
end
用发出异常来终止transaction
也可以用模块对象来呼出transaction
经常用@sample.save! 失败返回例外
事务隔离等级 |
用:isolation标签指定
:read_uncommitted
:read_committed
:repeatable_read
:serializable |
|
|
|
|
|
|
|
|
|
同时运行的管理 |
乐观锁 |
模块要追加列 |
追加lock_version:intefer
用命令行生成时候追加
已有的表格里也可以增加 |
在迁移文件中设置默认值 |
原来:t.intefer :lock_version
更改成:t.intefer :lock_version, default:
0 |
迁移 |
rails db:migrate |
设置/改变成隐藏输入框 |
《%= f.hidden_field :lock_version》
如果有显示lock_version的,要删掉 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
定义枚举的的域 |
用与设置数字与符号的对应
设置过程 |
以status:integer为例
设置默认值(非必须)
位置:db/migrate/ |
t.integer :status, default 0, null: false
|
设置枚举
位置:app/models/ |
用数组的话值是index(0开始)
enum status: [:draft, :published, :deleted] // 指定值用hash
enum status: {draft: 0, published: 1, deleted: 2}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
获取enum的值 |
@sample = @sample.find_by(...)
@sample.status |
设置值 |
@sample.status = 1
@sample.status = :published
@sample.published!
注: 设定没有定义好的值会出错, ArgumentError |
列举值作搜索范围 |
@sample = Sample.published
@sample = Sample.published.where(...) |
注意: |
设置enum以后validates的是字符串, 不是integer
|
|
|
|
|
|
|
|
|
|
|
|
其他更新类方法 |
P245 |
暂略
# TODO: |
|
|
实现验证功能(validation) |
ActiveModel可用的validation |
通用参数:
注: 可以直接设置成全部适用, 如 validates :id, allow_blank: true, length: { is: 10 }, uniqueness: true
或对特地验证适用, 如 validates :id, length: {allow_blank: true, is: 10}, uniqueness: true
allow_nil |
nil时跳过validation |
allow_blank |
nil和empty时跳过validation |
message |
修改报错信息 |
on |
validation的触发时刻
create |
新建时 |
update |
更新时 |
save |
create+update |
默认=:save
例: acceptance一般只要新建时同意条款
|
if |
条件成立时进行validation
参数:
字符串 |
validates :sample, presence: { if: "sample.method" }
作为代码运行
|
Proc式 |
直接运行, 参数是当前的instance |
symbol |
symbol对应的方法 |
|
unless |
条件不成立时进行validation |
with_options:
with_options(on: :create, if: 'true') do |oc|
oc.validates :name, presence: true
oc.validates :user_id, presence: true
end
ActiveModel可用的validation:
acceptance |
是否对checkbox打钩
参数:
不符合时的信息:
注:
● 不一定需要model有此列(自动生成同名假想列)
|
confirmation
|
待测text_field必须与_confirmation完全一致(如注册时的密码等)
参数: 无
不符合时的信息:
doesn't match confirmation
● 验证所用列不需要model有此列(自动生成加后缀_confirmation的假想列)
|
exclusion |
值是否不在指定数组/范围里
参数:
不符合时的信息:
|
inclusion |
值是否在指定数组/范围里
参数:
不符合时的信息:
is not included in the list
|
format |
是否符合正规表达式
参数:
不符合时的信息:
|
length |
检验字符串的长度
参数:
minimum |
最小长度 |
maximum |
最大长度 |
in |
长度范围(Range) |
tokenizer |
字符串分割方式(lamda式) |
is |
指定长度 |
too_long |
不符合maximum时的错误信息 |
too_short |
不符合minimum时的错误信息 |
wrong_length |
不符合is时的错误信息 |
不符合时的信息:
is too short(minimum is xxx characters)等
|
numericality |
检查数值大小/类型
参数:
only_integer |
只能是整数 |
greater_than |
必须大于 |
greater_than_or_equal_to |
必须大于等于 |
euqal_to |
必须等于 |
less_than |
必须小于 |
less_than_or_equal_to |
必须小于等于 |
odd |
必须是奇数 |
even |
必须是偶数 |
不符合时的信息:
|
presence |
值非null
参数: 无
不符合时的信息:
|
absence |
值必须为null
参数: 无
不符合时的信息:
|
uniqueness |
值必须唯一(unique)
参数:
scope |
决定unique的其他列
# 只需要此列值唯一
validates :column1, uniqueness: true
# 和一个列绑定
validates :column2, uniqueness: {allow_blank: true, scope: :a}
# 和多个列绑定
validates :column3, uniqueness: {allow_blank: true, scope: [:a, :b]}
设定了以后则, unique是指两列的组合(a, b)唯一
|
case_sensitive |
是否区分大小写
默认=true
|
不符合时的信息:
|
|
声明validate |
validates field [, ...] name: params [, ...]
参数含义:
filed |
需要检验的field名(可以多个) |
name |
validate类型 |
params |
相关validate类型的参数(没有就指定true) |
|
validate触发时机 |
触发时机 |
create, create! |
save, save! |
update, update! |
|
不触发的method |
increment! , decrement! |
increment_counter, decrement_counter |
toggle! |
touch |
update_all |
update_attribute |
update_counters |
update_column, update_columns |
save(validate: false) |
|
手动触发 |
valid? |
是否符合validation |
invalid? |
是否不符合validation |
|
|
errors |
errors (ActiveModel::Errors类)
前提: 设定了validates, 不然不会有任何错误
是否有错 |
|
获取错误数量 |
sample.errors.count
sample.errors.size
|
获取完整信息(错误信息的文本数组) |
sample.errors.full_messages
sample.errors.to_a
|
获取特定列的错误 |
sample.errors[:column_name]
sample.errors.details[:column_name]
|
手动添加错误 |
sample.errors.add(:column_name, 'error_message')
sample.errors[:column_name] << 'error_message'
|
清除错误 |
注: 只是清除errors里的,实际错误并没有消失
|
|
|
|
自定义validator1 |
直接呼出方法
validates :method_name [, ...]
|
自定义validator2 |
设置
# config/application.rb
# ...
module Core
class Application < Rails::Application
# ...
# add custom validators path
config.autoload_paths += Dir["#{config.root}/app/models/validators"]
config.enable_dependency_loading = true
# ...
end
end
创建文件
# app/models/validators/sample_validator.rb
class SampleValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
puts "UUID custom validate fired, options: #{options}" # 获取options的方法
record.errors[attribute.to_sym] << "test" # 错误通过此方法发出
end
end
使用
# sample.rb
# ...
class Sample < ApplicationRecord
# ...
validates :user_id, sample: {ko: "ok", sample1: 1}
# ...
end
# 运行 rails c
a = Sample.new
a.valid? # => false
# UUID custom validate fired, options: {:ko=>"ok", :sample1=>1}
|
定义不与数据库关联的model |
# TODO: 需要的时候完成此项 2019/02/21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
用关联(association)处理复杂表格 |
命名规则 |
外部键 |
sample_id
注: 主键默认为id |
中间表
(过渡表) |
用_按字母顺序连接
modelTest_viewTest |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
参照的设置 |
belongs_to assoc_id [,opt]
例: belongs_to :modeltest1
一对一关系
参数 |
|
位置 |
写在被参照的一方(即belongs_to的一方含有对方id)
含义: sample_id属于...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一对多 |
has_many assoc_id [,opt]
参数 |
|
位置 |
写在被参照的一方
由此被参照方可以获取参照方的数据 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一对一 |
has_one assoc_id [,opt]
参数 |
|
位置 |
写在被参照的一方
由此被参照方可以获取参照方的数据 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
多对多
m:n |
has_and_belongs_to_many assoc_id [,
opt]
参数 |
|
步骤 |
创建中间表
(过渡表) |
用_按字母顺序连接
modelTest_viewTest |
关联双方定义处
定义关联 |
has_and_belongs_to many |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
多对多2
m:n |
a---b---c这种情况下,直接关联a---c
has_many assoc_id, through: middle_id [,
opt]
例
b定义处
belongs_to :a
belongs_to :c
a定义处
has_many :b
has_many :c through: :b
c定义处
has_many :b
has_many :a through: :b |
由关联自动定义的方法 |
p282~283
# TODO:
略 |
关联可用的opt |
opt |
belongs_to |
has_one |
has_many |
has_and_belongs_to_many |
# TODO: Supply [选项的意义]
|
as |
X |
O |
O |
O |
多态(自己的名字) |
association_foreign_key |
X |
X |
X |
O |
m:n关联下的外部键
例: Book里的author_id
|
autosave |
O |
O |
O |
O |
父模型保存/删除时自动保存 |
class_name |
O |
O |
O |
O |
关联模型的类型 |
counter_cache |
O |
X |
O |
X |
获取数量时是否使用cache |
dependent |
O |
O |
O |
X |
删除模型时关联的模型也删除
:nullify |
默认, 什么都不做
foreign_id 变为nil
|
:destroy |
关联的model被删除时, 则呼出destory来删除
|
:delete |
关联的model被删除时, 则呼出delete来删除
● has_many时呼出的是delete_all
● 直接执行SQL, 所以不会对自身关联的其他model有影响
|
|
|
|
foreign_key |
O |
O |
O |
O |
使用的外部键名称 |
join_table |
X |
X |
X |
O |
使用的结合表格名称 |
optional |
O |
X |
X |
X |
不检查关联的对象是否存在 |
primary_key |
O |
X |
O |
X |
关联时使用的主键列的名称 |
polymorphic |
O |
X |
X |
X |
多态关系的有效化?
# TODO: Supply [选项的意义]
|
readonly |
X |
X |
X |
O |
设置关联的对象只可读 |
required |
O |
X |
X |
X |
检查关联对象是否存在 |
touch |
O |
X |
X |
X |
保存的时候关联的对象的create_at/updated_at也更新 |
source |
X |
O |
O |
X |
对于 has_many:through , 指定源头(即本model的名称)
只有在指定的关联名称不是对方model名(即使用class_name时)才需要
|
through |
X |
O |
O |
X |
|
validate |
O |
O |
O |
O |
设置保存的时候是否检查关联的对象 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
与相关model结合 |
joins(exp)
前提是已经建立association
● 参数是关联名(如has_one则为单数)
● 搜索时候套上的symbol是表格名
cars = cars.includes(:equipment_spec).where(equipment_specs: request)
exp |
结合条件
A. 关联名(Symbol) |
Car.joins(:equipment_spec).select('cars.*, equipment_specs.*')
|
B.关联名1: 关联名2 |
关联名1和关联名2也关联
EquipmentSpec.joins(car: :maker) .select('equipment_specs.*, cars.id AS car_id, makers.name AS maker_name')
|
C. 字符串
SQL
|
用于INNER JOIN以外的结合(LEFT JOIN/ RIGHT JOIN) |
|
|
|
|
必须要带上select,
不然虽然结合了但只获取了当前的model
EquipmentSpec.joins(:car).select('equipment_specs.*, cars.*')
|
用join也能达到association的效果
|
与相关model结合
(左外部结合)
Rails 5.0
|
left_outer_joins(exp)
alias: left_joins(exp)
结合是左外部结合 LEFT OUTER JOIN
写法和上面一样, 但不能用C写法
● 参数是关联名(如has_one则为单数)
● 搜索时候套上的symbol是表格名
|
和相关model一起获取 |
includes(exp)
结合是左外部结合 LEFT OUTER JOIN
写法一样,但不能用C写法
● 参数是关联名(如has_one则为单数)
● 搜索时候套上的symbol是表格名
|
|
|
回调(call back) |
|
用例:注册时候每天的空白自动生成
注册或者更新时候自动发邮件
注册更新时保存为履历等 |
回调函数 |
主要方法 |
各时间点所对应函数
新建,更新,删除 |
create/create!, destroy/destroy!,
destroy_all
increment!,
decrement!, save/save!, toggle!, update/update!,
update_attribute, valid?
红色: 之前跳过的 |
after_find |
搜索数据库后
all,first, find, find_by, find_by_sql
|
after_initialize |
new来生成或者读取数据库后 |
回调函数
创建 |
更新 |
删除 |
运行时间 |
before_validation |
|
|
验证处理前 |
after_validation |
|
|
验证处理后 |
before_save |
|
|
保存前 |
around_save |
|
|
保存前后 |
before_create |
before_update |
before_destroy |
新建/更新/删除前 |
around_create |
around_update |
around_destroy |
新建/更新/删除前后 |
after_create |
after_update |
after_destroy |
新建/更新/删除后 |
after_save |
|
|
保存后 |
after_commit |
|
|
commit后? |
after_rollback |
|
|
回调后 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
迁移文件 |
位置 |
app/db/migrate/ |
生成migration文件 |
本页最上面找 |
构造 |
schame处理 |
change方法内部 |
迁移文件的版本信息 |
class CreateEquipmentCars < ActiveRecord::Migration[5.0]
#...
end
ActiveRecord::Migration[5.0]部分 用后面的Migration[版本]来控制
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
逻辑方法 |
|
主要方法 |
tname: table name
frname: 外部table name
fname: field name
type: field的数据类型
opt: field的option
i_opt: index option
t_opt:table option
fr_opt: foreign key option
create_table
change_table
|
create_table tname [,toption] do |t|
t.type fname [, opt, ...]
...
end
create_table, change_table内部可用方法搜[create_table,change_table代码块内可用的方法]
tname |
表格名 |
toption
表格选项
|
选项
id |
是否自动生成主键
默认: true |
primary_key |
主键的名称
默认: id
改变默认主值: |
set_prime_key '...' |
位置: |
模型类
Model Class |
|
temporary |
是否作为暂时的表格
默认: false |
force |
创建前是否删除已有的表格
默认: false |
options |
其他的表格选项
暂时不管
p301
# TODO: |
|
|
|
|
|
|
追加列 |
add_column(tname, fname, type [, opt]) |
追加索引 |
add_index(tname, fname [, i_opt]) |
追加外部键 |
add_foreign_key(tname, frname [,
fr_opt])
tname: 表格名
frname: 参照的表格名
注: foreign_key追踪的primary_key(默认xxx_id),必须设有index
|
追加
create_at
update_at |
add_timestamps(tname) |
改变已有列 |
change_column(tname, fname, type [,
opt]) |
是否允许该列可以有null |
change_column_null(tname, fname, null)
null: true为不允许无效值
false允许 |
改变默认值 |
change_column_default(tname, fname,
default) |
改变表格 |
change_table(tname)
create_table, change_table内部可用方法搜[create_table,change_table代码块内可用的方法]
|
确认指定列是否存在 |
column_exists?(tname, fname [, type
[,opt]]) |
创建表格 |
create_table(tname [,t_opt])
最上面那个就是 |
创建中间表格 |
create_join_tabble(tname1, tname2 [,
t_opt]) |
删除已有表格 |
drop_table(tname [, opt]) |
确认索引是否存在 |
index_exists?(tname, fname [i_opt]) |
删除一个列 |
remove_column(tname, fname [, type,
opt]) |
删除多个列 |
remove_columns(tname, fname [,...]) |
删除已有的索引 |
remove_index(tname [, i_opt]) |
删除外部键 |
remove_foreign_key(tname, frname) |
重命名列 |
rename_column(tname, old, new) |
重命名索引 |
rename_index(tname, old, new) |
重命名表格 |
rename_table(tname, new) |
执行sql指令 |
execute(sql) |
t.string等的
opt
|
limit |
列的位数
字符: 字符长度
数字: 数字的字符长度(包含一切元素,如小数点) |
defalut |
默认值 |
null |
是否允许null值
默认true |
precision |
数值的总位数
123.123 六位 |
scale |
小数点以下的位数 |
polymorphic |
belong_to关联所用的列 |
index |
是否生成索引 |
comment |
列的说明 |
after |
指定在哪一列的后面 |
|
t_opt
table option |
id |
是否自动生成主键
默认: true |
primary_key |
主键的名称
默认: id
改变默认主值: |
set_prime_key '...' |
位置: |
模型类
Model Class |
|
temporary |
是否作为暂时的表格
默认: false |
force |
创建前是否删除已有的表格
默认: false |
options |
其他的表格选项
暂时不管
p301
# TODO:
|
|
i_opt
index opt
|
unique |
是否保证每一个索引独一无二 |
name |
索引名字 |
length |
索引包含的列的长度
length: {col1: 10, col2: 20}
好处: 加快运行速度 |
|
fr_opt |
collum |
外部key的名字
默认: 参照的model_id
|
primary_key |
参照model的主key
默认: id
|
name |
?? |
on_delete |
参照的model删除时的动作
默认:restrict
:nullify |
设置成null |
:cascade |
更新 |
:restrict |
报错
错误信息: 违反外部key制约
|
|
on_update |
参照的model更新时的动作
同上
|
|
|
create_table,
change_table
代码块内可用的方法
|
create_table,change_table代码块内可用的方法
例:
change_table tname do |t|
...
end
● 可用的方法
t.index |
例: t.index
相当于不在change_table代码块下的add_index
|
t.change |
相当于不在change_table代码块下的change_column |
t.change_default |
相当于不在change_table代码块下的change_column_default |
t.rename |
相当于不在change_table代码块下的rename_column |
t.remove |
相当于不在change_table代码块下的remove_column |
t.remove_references |
相当于不在change_table代码块下的remove_foreign_key |
t.remove_index |
相当于不在change_table代码块下的remove_index |
t.remove_timestamps |
相当于不在change_table代码块下的remove_timestamps |
|
|
● 可用的列定义
可利用的数据类型和对应关系
迁移(fname)
写在迁移文件里
例: t.string :str
|
SQLite |
Ruby |
integer |
INTEGER |
Fixnum
(就是Ruby里的普通整数)
4byte
|
bigint |
BIGINT |
8byte |
decimal |
DECIMAL |
BigDecimal
(高精度小数)
|
float |
FLOAT |
Float |
string |
VARCHAR(255) |
String |
text
注: 不能设为index
因为长度太长
|
TEXT |
String |
binary |
BLOB |
String |
date |
DATE |
Date |
datetime |
DATETIME |
Time |
timestamp |
DATETIME |
Time |
time |
TIME |
Time |
boolean |
BOOLEAN |
TrueClass/FalseClass |
特殊的 |
|
|
timestamps |
自动创建created_at和updated_at
列生成与更新的时候自动设定
|
references
相当于
belongs_to
|
外部键
例
t.references :book #生成book_id,相当于 t.belongs_to :book
注: 参数是参照名, 可以不是table名。实际rails使用的都是单数来呼出
选项(()内为默认值): index: (true), polymorphic: (false)
|
|
|
|
|
|
|
选项opt
limit |
列的位数 字符: 字符长度 数字: 数字的字符长度(包含一切元素,如小数点) |
defalut |
默认值 |
null |
是否允许null值 默认true |
precision |
数值的总位数 123.123 六位 |
scale |
小数点以下的位数 |
polymorphic |
belong_to关联所用的列 |
index |
是否生成索引 |
comment |
列的说明 |
after |
指定在哪一列的后面 |
|
模型处改变迁移文件数据类型 |
attribute(name, type [,default:
value]) |
迁移文件的生成 |
和模型一起生成 rails generate model name field:type
[...] [options]
单独生成 rails generate migration name [field:type
...] [options] |
删除或者增加列 |
生成迁移文件时候命名
rails g model AddXxxxTo表格名
增加 |
AddXxxxTo表格名 |
删除 |
RemoveXxxxFrom表格名 |
|
rails generate migration AddBirthToAuthors
birth: date |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
升级与回滚 |
原则 |
基本上所有方法都写在change里面 |
可以自动被回滚的方法 |
add_column |
|
add_index |
|
add_reference |
|
add_timestamps |
|
change_table |
呼出change/change_default/remove的不能自动回滚 |
create_table |
|
create_join_table |
|
remove_timestamps |
|
rename_column |
|
rename_index |
|
rename_reference |
|
rename_table |
|
|
无法回滚时的方法 |
增加回滚的信息
remove_column/drop_table
|
remove_column |
在后面写上被删除的列的详细信息即可
remove_column(tname, fname [, type, opt])
注意: remove_columns无法追加详细信息
|
drop_table |
写法和create_table一样 |
|
升降级处理分开写
reversible
|
reversible do |dir| # dir: 管理回滚的对象
dir.up do
... # 升级时的处理
end
dir.down do
... # 降级时的处理
end
end
|
写在单独的up/down方法里 |
def up
... # 升级时的处理
end
def down
... # 降级时的处理
end
|
|
|
|
|
|
|
|
|
schema来构筑数据库 |
schema文件位置 |
位置/app/db/schema.rb |
意义 |
自动获取最新的数据库表格信息
和迁移文件一样可能会有无法展现的对象(object) |
放弃现在的数据库,
用schema来构筑最新的数据库 |
rails db:reset
windows环境下加DISABLE_DATABASE_ENVIROMENT=1
注意: 只是重构,测试数据要另外读取 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
数据库初始化 |
迁移和初始化一起 |
rails db:setup
相当于
rails db:create:all
rails db:migrate
rails db:seed 或者 rails
db:fixtures:load |
seed file |
初始数据来初始化(也可以用fixture)
位置 |
db/seed.rb
可能需要自己新建 |
形式 |
ruby脚本 |
内容 |
只需要写生成/保存数据的代码
如Sample.new(...)
|
运行 |
rails db:seed |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fixture |
测试数据来初始化(也可以用seed)
位置 |
test/fixtures/
表格名.rb |
形式 |
yaml脚本
注: 缩进只能用手打两个空格 |
内容 |
标签:
域名: 数值
...
外部键间接写法
仅yml文件内可用 |
模型名: 标签 |
缩进 |
手打的2个空格 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
运行 |
rails db:fixtures:load
指定读取文件
位置: /test/fixtures/... |
FIXTURES=sample1, samples2, ...
默认: 读取全部 |
指定测试环境 |
RAILS_ENV=prodution/test/development
默认: development |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Data/Time相关的有用的方法 |
yesterday |
昨天 |
tomorrow |
明天 |
prev_xxxx |
前年/月/周(year,month,week) |
next_xxxx |
下年/月/周(year,month,week) |
beginning_of_xxxx |
年/季/月/周的开始一天(year, quarter, month, day) |
end_of_xxxx |
年/季/月/周的最后一条(year, quarter, month, day) |
|
|
n.xxx.ago
Numeric |
n个年/月/日/时/分/秒以前
years, months, days, hours, minutes, seconds
也可以用单数 |
n.xxx.from_now
Numeric |
n个年/月/日/时/分/秒以后
years, months, days, hours, minutes, seconds
也可以用单数 |
|
|