Rails5 Model Document

创建: 2017/06/09

更新: 2017/06/21

更新: 2017/06/23 对待未完成的追加# TODO:
更新: 2017/06/29 修正文件名db/seed.rb ---> db/seeds.rb
                          改变默认主值 set_prime_key '...'
更新: 2017/08/06 纠正错误:where返回找到的全部
                          belongs_to 写在参照的一方 ---> 写在被参照的一方  
                          增加生成数据库指令        rake db:create:all
更新: 2017/08/17 对rails db:setup 详细解释
更新: 2017/10/15 增加了AddXxxToXxx的例子
更新: 2017/10/28 修正[RemoveXxxxFrom表格名](To ---> From)
更新: 2017/10/29 修正拼写错误 destory--->destroy
更新: 2018/01/08 增加 find_or_create_by
                          补充 new=build, create = new + save
更新: 2018/01/16 增加迁移的选项after
更新: 2018/01/17 增加创建时间
更新: 2018/02/09 增加change_table下能利用的方法的写法例: t.index
更新: 2018/02/10 大幅度补充了迁移文件相关内容 
更新: 2018/02/13 增加association的相关opt
更新: 2018/02/28 更新迁移文件里的选项是否允许null值 [NULL] -> [null]
更新: 2018/04/02 补充migration相关说明
更新: 2018/04/17 纠正 [have] -> [having]
                         补充model的结合搜索
更新: 2018/04/22 补充关联的dependent选项的说明
                      补充delete, destory区别
          补充includes, joins相关注意: [参数是关联名, 检索套上的是表格名]
更新: 2018/05/02  增加 has_attribute?
更新: 2018/8/28 补充migration相关细节
更新: 2018/09/28 在migration处补充rails g migration的位置
更新: 2019/01/16 补充where里not的写法
更新: 2019/02/07 补充belongs_to包含对方id的说明
          补充t.reference, t.belongs_to参数说明
          修改destory_all, delete_all描述(原来的写反了)
          增加了delete, delete_all, destroy, destroy_all的sql执行情况说明
更新: 2019/02/12  补充t.decimal的说明: [ (高精度小数)]
更新: 2019/02/13  补充foreign_key追踪的primary_key必须设有Index
更新: 2019/02/21  增加(补充)validation相关内容
          删除多余的行
         更新部分连接(迁移到博客园前的链接改成博客园的新链接) (更改处: model-生成)
         增加待完成事项
更新: 2019/02/22 对validation进行补充和修正
          补充了设置enum后的注意点
更新: 2019/04/02 补充了has_one, has_many的source选项
更新: 2019/04/05 补充了text类型不能设为index
更新: 2019/04/16 补充validates的uniqueness的scope可以设置多个(用数组)

待完成事项: TODO

 
模型(model)
 模型(model)
 生成 rails generate model name field:type [...] [options]
 P48
# TODO: options
类型首字母不大写
 app

例子: 

rails g model questionnaire question:string 

veryAgree:boolean agree:boolean

disagree:boolean veryDisagree:boolean


 

迁移文件的生成

和模型一起生成 rails generate model name field:type [...] [options]
 单独生成 rails generate migration name [field:type ...] [options]

例: rails generate migration AddBirthToAuthors birth: date

     生成的文件名 20180216002328_add_birth_to_authrs.rb

     文件内容

#20180216002328_add_birth_to_authrs.rb

class AddBirthToAuthors < ActiveRecord:: Migration[5.0] 
  def change 
    add_ column :authors, :birth, :date 
  end 
end

 

 

 自带属性 
 概要 键名
 主键(自动生成) id
 记录(record)的生成时间  created_at 
 记录(record)的更新时间 updated_at
 rails命令行 命令行测试模块(model)
 启动 rails console opts
 指定运行环境 rails console test/development/production
 默认development
 不保留变更 -s
 --sandbox 
  
  
  
 新建 test = modelTest.new(hp: 1200, mp:9999, ad: 12345)
 保存 test.save
 获取最后一个数据 last = ModelTest.last
 退出命令行 quit
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 查看履历  rails db:migrate:status
------------------------------------------------------------------------------
Rails5 <wbr>Model <wbr>Document
------------------------------------------------------------------------------
 生成数据库 rake db:create:all
 设定数据库 rails db:migrate
 db:migrate
 
 运行到指定的版本处(VERSION=...)
 不指定就是用最新版,把所有没迁移的全部迁移了
例: rails db:migrate VERSION=20161205000859
 db:rollback 回滚指定步
例: rails db:rollback STEP=5
 db:migrate:redo 回滚指定步并且重新迁移
例: rails db:migrate:redo STEP=5
 db:migrate:reset 先删除数据库,然后重新生成并且迁移最新版本
例: rails db:migrate:reset 
删除production环境下的数据库
DISABLE_DATABASE_ENVIRONMENT_CHECK=1
windows下删除development下数据貌似也要p312
# TODO:
 选项 
 RAILS_ENV 设置测试用数据库环境: production, development, test
 默认 RAILS_ENV=development
 VERBOSE 是否在命令行输出迁移的过程
 默认true
 VERBOSE=false
  
  
  
 
生成并读取数据库  rails db:setup
相当于
         rails db:create:all
         rails db:migrate
         rails db:seed 或者 rails db:fixtures:load
 schema来构筑数据库
schema文件位置 位置/app/db/schema.rb
 意义 自动获取最新的数据库表格信息
 和迁移文件一样可能会有无法展现的对象(object)
 放弃现在的数据库,
 用schema来构筑最新的数据库
 rails db:reset
windows环境下加DISABLE_DATABASE_ENVIROMENT=1

注意: 只是重构,测试数据要另外读取
  
  
  
  
  
  
  
 seed 初始数据来初始化(也可以用fixture)
 位置 db/seeds.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
  
  
  
 读取 rails db:fixtures:load (FIXTURES=samples)
 初始化 rails db:reset (DISABLE_DATABASE_ENVIROMENT_CHECK=1)
 括号内内容是删除production模式的数据库
 windows下development模式好像也要
 删除 rails db:drop:all  (DISABLE_DATABASE_ENVIROMENT_CHECK=1)
 括号内内容是删除production模式的数据库
 windows下development模式好像也要
服务器客户端  
启动 rails db
 或 rails dbconsole
 表格一览 .tables
 确认特定表格结构 .schema samples
 表格内容一览 SELECT * FROM samples;
 关闭客户端 .quit
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
基本的数据检索
 主键(key)搜索 Class.find(keys)
  返回主键所对应的数据(一对一)
 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

 
AVG(sample)  AS avg_price 

 呼出列

 Class.avg_price

 

 select中使用SQL函数 例: Book.select('AVG(sample) AS avg_sample')
用AS设定名称
  
  
 去除重复 Class.where(...).distinct(flag)
 Class.select(...).distinct(flag)
 flagtrue 去除重复 
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})
Rails5 <wbr>Model <wbr>Document
 新建+保存 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打钩

 参数:

 accept

 必须与指定的值一致

 默认=1

  

 不符合时的信息:

must be accepted

 注:

 ● 不一定需要model有此列(自动生成同名假想列)

 

 confirmation

 

 待测text_field必须与_confirmation完全一致(如注册时的密码等)

 参数: 无

 不符合时的信息: 

doesn't match confirmation

  ● 验证所用列不需要model有此列(自动生成加后缀_confirmation的假想列)

  exclusion 

 值是否不在指定数组/范围里

 参数:

 in 指定数组/范围
  

 不符合时的信息: 

is reserved

 

 inclusion 

 值是否在指定数组/范围里

 参数:

 in 指定数组/范围
  

 不符合时的信息: 

is not included in the list

 

 format

 是否符合正规表达式

 参数:

 with 正规表现
  

 不符合时的信息: 

is invalid

 

 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 必须是偶数

 不符合时的信息: 

is not a number 等

 

 presence

 值非null

 参数: 无

 不符合时的信息: 

can't be blank

 

 absence 

 值必须为null

 参数: 无

 不符合时的信息: 

must be blank

 

 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 

 不符合时的信息: 

has already been taken

 

 

 声明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.any?

 

 获取错误数量 
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'

 

 清除错误

 

sample.errors.clear

 

 注: 只是清除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
 一对一关系
 参数 
 assoc_id 被关联的模块名
 单数
 opt 
 位置

 写在被参照的一方(即belongs_to的一方含有对方id)

 含义: sample_id属于...

  
  
  
  
  
  
  
  
 一对多 has_many assoc_id [,opt]
 参数 
 assoc_id 被关联的模块名
 复数
 opt 
 位置 写在被参照的一方
 由此被参照方可以获取参照方的数据
  
  
  
  
  
  
  
  
 一对一 has_one assoc_id [,opt]
 参数 
 assoc_id 被关联的模块名
 单数
 opt 
 位置 写在被参照的一方
 由此被参照方可以获取参照方的数据
  
  
  
  
  
  
  
  
 多对多
 m:n
 has_and_belongs_to_many assoc_id [, opt]
 参数 
 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[版本]来控制
  
  
  
  
  
  
  
  
 逻辑方法

 

 判断是否存在某列 has_attribute?
  
  
  
  
  
  

 

 主要方法

 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
  

 

 

 ● 可用的列定义

t.数据类型 :列名, opt

 可利用的数据类型和对应关系

 迁移(fname)

 写在迁移文件里

 例: t.string :str

 

 SQLite Ruby
 integer INTEGER  Fixnum
 (就是Ruby里的普通整数)
 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
也可以用单数
  

 

转载于:https://www.cnblogs.com/lancgg/p/8281811.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值