1、ApplicationRecord

在Rails4中所有的模型都继承自ActiveRecord::Base,不过在Rails5中新引进了一个叫ApplicationRecord的类,存放在: app/models/application_record.rb中,所有Rails5应用都会有这个类, 它的内容非常简单:

class ApplicationRecord < ActiveRecord::Base  
     self.abstract_class = true
   end

就是一个继承ActiveRecord::Base的抽象类,作用就是为整个应用程序模型提供一个自己的基类

module MyModule
  end
  # Rails4.x中扩展模型的方式
  ActiveRecord::Base.send :include, MyModule
  # Rails5
  class ApplicationRecord < ActiveRecord::Base
    include MyModule
    self.abstract_class = true
  end

2、OR语法支持(查询语句的组合查询),Rails5中提供了对两个AR Relation对象的OR方法:

> Article.where(user_id: 1).or(Article.where(user_id: 2))

=> Article Load (2.5ms)  SELECT `articles`.* FROM `articles` WHERE (`articles`.`user_id` = 1 OR `articles`.`user_id` = 2)

需要注意的是如果你在第一个Relation中是用了:limit distinct offset 这三个方法的话,那么就必须在后面的Relation中也使用相同的方法,否则的话就会报错

> Article.where(user_id: 1).limit(1).or(Article.where(user_id: 2))
#=>ArgumentError: Relation passed to #or must be structurally compatible. Incompatible values: [:limit]

最好是在结尾使用:

Article.where(user_id: 1).or(Article.where(user_id: 2)).limit(1)

3、ActiveRecord::Relation#cache_key

Rails中使用缓存是很常见的行为,通常我们要缓存一组查询出来的记录,需要手动的设置缓存的key

no_nick_name_users = User.where(nick_name: nil)
cache_key = [User.name, 'no_nick_name_users', no_nick_name_users.maximum(:updated_at).to_i]
Rails.cache.fetch(cache_key) do
  no_nick_name_users.to_a
end

Rails5中提供了ActiveRecord::Relation#cache_key

no_nick_name_users = User.where(nick_name: nil)
Rails.cache.fetch(no_nick_name_users.cache_key) do
  no_nick_name_users.to_a
end
puts no_nick_name_users.cache_key
#=> "users/query-dae9b6f1d9babd4a9ec4c532614c29eb-1-20160703095605000000"

上面最后一行,Rails5提供的cache_key和我们自己设置的很相似,分别有5个组成部分分别是:

users : 表名
    query : 常值
    dae9b6f1d9babd4a9ec4c532614c29eb : 缓存SQL的MD5码
    1 : 结果集数量
    20160703095605000000 : 结果集最大的updated_at的时间戳

4、AR Relation调用update会触发callbacks和validates

在Rails4中的AR Relation 提供了两个更新记录的方法update_all和update其中:

update_all 通过一条SQL语句更新多条记录,不能触发callback和validate
    update 通过N条SQL语句,更新N条记录,其中N取决于其第一个ID参数的个数。

通过上面的方法定义,可以看出,如果你不知道ID的情况下,想更新一组记录并且触发它们各自的callback和validate,在Rails4中是做不到的。
那么在Rails5中修改了AR Relation#update的实现:

def update(id = :all, attributes)
   if id.is_a?(Array)
     id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
   elsif id == :all
     to_a.each { |record| record.update(attributes) }
   else
     object = find(id)
     object.update(attributes)
    object
  end
end

也就是亦可以通过下面的方法更新记录:

2.3.0 :007 > User.where(nick_name: 'Falm').update(nick_name: 'falm')
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`nick_name` = 'Falm'
   (0.1ms)  BEGIN
  SQL (0.3ms)  UPDATE `users` SET `nick_name` = 'falm', `updated_at` = '2016-07-03 05:00:18' WHERE `users`.`id` = 1
   (2.0ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.2ms)  UPDATE `users` SET `nick_name` = 'falm', `updated_at` = '2016-07-03 05:00:18' WHERE `users`.`id` = 2
   (0.3ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.2ms)  UPDATE `users` SET `nick_name` = 'falm', `updated_at` = '2016-07-03 05:00:18' WHERE `users`.`id` = 3
   (0.2ms)  COMMIT
   (0.1ms)  BEGIN
  SQL (0.2ms)  UPDATE `users` SET `nick_name` = 'falm', `updated_at` = '2016-07-03 05:00:18' WHERE `users`.`id` = 4
   (0.2ms)  COMMIT

更新操作被按ID分解成多个update语句,并且其中每一个都会执行callback和validates, 要注意的是如果你要更新的记录不必要触发callback或validates,那么因为性能原因最好使用update_all方法。
更新记录时,不更新updated_at/updated_on

Rails4.x中,更新记录是,AR都会连带更新,记录上的updated_at或updated_on字段。
在Rails5中,为ActiveRecord::Base#save方法提供了一个选项,touch: boolean,默认情况下是true,如果设置成false的话,更新记录是就不会更新updated_at字段了。

2.3.0 :027 > user = User.first
  User Load (0.3ms)  SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
 => #<User id: 1, phone: "13303300333", email: nil, sign_in_count: 0, name: "Jason", nick_name: "falm", encrypted_password: nil, created_at: "2016-07-03 05:00:14", updated_at: "2016-07-03 05:00:18">
2.3.0 :028 > user.phone = '15088833388'
 => "15088833388"
2.3.0 :029 > user.save(touch: false)
   (0.2ms)  BEGIN
  SQL (0.3ms)  UPDATE `users` SET `phone` = '15088833388' WHERE `users`.`id` = 1
   (0.4ms)  COMMIT
 => true
2.3.0 :030 > user.updated_at
 => Sun, 03 Jul 2016 05:00:18 UTC +00:00

5、忽略字段

Rails5中新增了 ActiveRecord::Base.ignored_columns 方法,用于忽略数据表中不需要的字段(model中定义忽略的字段)。

class User < ApplicationRecord
  self.ignored_columns = ['sign_in_count']
end

这样在模型中就不会有这个字段了

2.3.0 :033 > User.first
  User Load (0.2ms)  SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
 => #<User id: 1, phone: "15088833388", email: nil, name: "Jason", nick_name: "falm", encrypted_password: nil, created_at: "2016-07-03 05:00:14", updated_at: "2016-07-03 05:00:18">

6、Belongs_to关联,默认必填

在Rails5中AR中的belongs_to 关联,默认情况下是不能为空的:

class User < ApplicationRecord
end
class Article < ApplicationRecord  
  belongs_to :user
end
> Article.create(title: 'without user').errors.full_messages.to_sentence
   (0.2ms)  BEGIN
   (0.1ms)  ROLLBACK
 => "User must exist"

Article属于User,但是如果没有在创建时指定user的话,就无法通过AR的validates,如果你想去除这个默认选项的话,可以通过下面的方式:

class Article < ApplicationRecord  
  belongs_to :user, optional: true, #指定可选
end

也可以在application.rb中全局设置这个特性为可选的。

Rails.application.config.active_record.belongs_to_required_by_default = false

7、新的 after_{create,update,delete}_commit 回调

在Rails4中,我们可以在模型中设置事务执行后的回调方法,

# == Schema Information
#
# Table name: users
#
#  id                 :integer          not null, primary key
#  phone              :string(255)      not null
#  email              :string(255)
#  sign_in_count      :integer          default(0)
#  name               :string(255)      not null
#  nick_name          :string(255)
#  encrypted_password :string(255)
#  created_at         :datetime         not null
#  updated_at         :datetime         not null
#
class User < ApplicationRecord
  after_commit :send_message, on: :create
  after_commit :send_message, on: :update
  after_commit :send_message, on: :destroy
  private
  def send_message
    do_someting
  end
end

以上就是分别在 创建,更新,和删除事务执行后,被调用的回调方法
那么在Rails5中给它们分别提供的单独的别名方法:

class User < ApplicationRecord
  after_create_commit :send_message
  after_update_commit :send_message
  after_destroy_commit :send_message
  private
  def send_message
    do_someting
  end
end

8、rails4中执行数据迁移使用rake,rails5中为了不来回切换而统一使用rails即可:

rails 4:rake db:migrate

rails 5:rails db:migrate

9、支持在migration中添加comments

在大多数的项目中,快速变化的业务模型是很常见的事情,随之而来的就是数据模型的频繁变化,在这种场景下,我们通常会使用 migration_comments + annotate_models 这两个gem 去为模型添加注释信息,以便能够更好的解释模型的由来和用途。现在Rails5原生支持了 migration_comments的功能:

#encoding: utf-8
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users, comment: '用户表' do |t|
      t.string :phone, null: false, comment: '手机号'
      t.string :email, comment: '邮箱'
      t.integer :sign_in_count, default: 0, comment: '登录次数'
      t.string :name, null: false, comment: '用户名'
      t.string :nick_name, comment: '昵称'
      t.string :encrypted_password, comment: '加密密码'
      t.timestamps
    end
  end
end

运行迁移:

$> rails db:migrate
== 20160703025729 CreateUsers: migrating ======================================
-- create_table(:users, {:comment=>"用户表"})
   -> 0.0178s
== 20160703025729 CreateUsers: migrated (0.0179s) =============================

在mysql数据库中也可以查看到注释:

mysql> show full columns from users;
+--------------------+--------------+-----------------+--------+-------+-----------+----------------+---------------------------------+-----------+
| Field              | Type         | Collation       | Null   | Key   |   Default | Extra          | Privileges                      | Comment   |
|--------------------+--------------+-----------------+--------+-------+-----------+----------------+---------------------------------+-----------|
| id                 | int(11)      | <null>          | NO     | PRI   |    <null> | auto_increment | select,insert,update,references |           |
| phone              | varchar(255) | utf8_general_ci | NO     |       |    <null> |                | select,insert,update,references | 手机号    |
| email              | varchar(255) | utf8_general_ci | YES    |       |    <null> |                | select,insert,update,references | 邮箱      |
| sign_in_count      | int(11)      | <null>          | YES    |       |         0 |                | select,insert,update,references | 登录次数  |
| name               | varchar(255) | utf8_general_ci | NO     |       |    <null> |                | select,insert,update,references | 用户名    |
| nick_name          | varchar(255) | utf8_general_ci | YES    |       |    <null> |                | select,insert,update,references | 昵称      |
| encrypted_password | varchar(255) | utf8_general_ci | YES    |       |    <null> |                | select,insert,update,references | 加密密码  |
| created_at         | datetime     | <null>          | NO     |       |    <null> |                | select,insert,update,references |           |
| updated_at         | datetime     | <null>          | NO     |       |    <null> |                | select,insert,update,references |           |
+--------------------+--------------+-----------------+--------+-------+-----------+-----------

rails 5 功能新增及改变的更多相关文章

  1. Java第十二次作业:什么是一维数组?什么是对象数组?吃金币游戏2.0版 新增炸弹功能 新增游戏倒计时功能 新增胜利失败检测功能 使用如鹏游戏引擎制作窗体 一维数组设置金币

    什么是数组? 数组的定义:是用统一的名字代表这批数据,用序号来区分各个数据.数组是无序的数据元素按有序的下标组成的集合,分配固定空间大小的一种容器. 如何理解:其实就是一个同时放很多数据的变量. a= ...

  2. java在线聊天项目0.4版本 制作服务端接收连接,客户端连接功能 新增客户端窗口打开时光标指向下边文本域功能,使用WindowListener监听WindowAdapter

    建一个服务端类ChatServer,用于设置端口接收连接 package com.swift; import java.io.IOException; import java.net.ServerSo ...

  3. RandomAccessFile()实现用户注册功能, 新增,查询,更新

    package seday03.raf;import java.io.IOException;import java.io.RandomAccessFile;import java.util.Arra ...

  4. Windows Server 2016-DNS 新增或改进功能

    本章节补充介绍在 Windows Server 2016 中域名系统 (DNS) 服务器新增或已更改的功能相关信息,具体内容如下: 功能 新增或改进 描述 DNS 策略 新增 您可以配置 DNS 策略 ...

  5. Excelize 2.5.0 正式发布,这些新增功能值得关注

    Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准.可以使用它来读取.写入由 Microsoft Exc ...

  6. SCVMM之Windows Server2012 R2新功能

    在Windows Server 2012 R2中可以通过使用共享的虚拟硬盘VHDX文件的方法来模拟IP SAN,来为虚拟机创建群集提供共享存储.这样为虚拟机创建群集时就不用再像以前一样通过使用软件模拟 ...

  7. Rails 建立一个资源

    在blog 应用程序中.你可以通过脚手架(scaffolded)开始建立一个资源. 这将是单一的blog 提交.请输入以下命令 $ rails generate scaffold Post name: ...

  8. 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...

  9. iOS 10 都有什么改变?

    iOS 10 都有什么改变? 看这一个贴就够了 最全面的试用 苹果在 WWDC 2016 发布会上正式发布了 iOS 10 操作系统,iOS 与 macOS.tvOS 和 watchOS 构建了苹果四 ...

随机推荐

  1. linux日常笔记(1)

    1.SELlinux SELinux是 美国国家安全局 (NSA) 对于 强制访问控制的实现 =>可以使root受限的权限 关闭SELinux=>修改配置文件,永久生效; sed -i ' ...

  2. pat 1006 Sign In and Sign Out(25 分)

    1006 Sign In and Sign Out(25 分) At the beginning of every day, the first person who signs in the com ...

  3. 正则表达式 第五篇:C# 正则元字符

    本文整理C#正则表达式的元字符,正则表达式是由字符构成的表达式,每个字符代表一个规则,表达式中的字符分为两种类型:普通字符和元字符.普通字符是指字面含义不变的字符,按照完全匹配的方式匹配文本,而元字符 ...

  4. beta week 1/2 Scrum立会报告+燃尽图 02

    此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/9912 一.小组情况 队名:扛把子 组长:孙晓宇 组员:宋晓丽 梁梦瑶 韩昊 ...

  5. 程序员常用6 个 Python 的日期时间库

    内建的 datetime 模块 在跳转到其他库之前,让我们回顾一下如何使用 datetime 模块将日期字符串转换为 Python datetime 对象. 假设我们从 API 接受到一个日期字符串, ...

  6. Spring中常见的设计模式——单例模式

    一.单例模式的应用场景 单例模式(singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.J2EE中的ServletContext,ServletCon ...

  7. 从Netty EventLoop实现上可以学到什么

    本文主要讨论Netty NioEventLoop原理及实践,关于Netty NioEventLoop,首先要知道NioEventLoop是什么,为什么它会是Netty核心Reactor处理器,实现原理 ...

  8. 有效的减少代码中太多的if、else?-策略模式

    写这篇文章的目的和上一篇单例模式一样,策略模式也是一种常用的设计模式,太多的if-else不仅看着不太美观而且不好维护,对于自己来说也等于复习了一遍策略模式.先说一下策略 模式的定义: 策略模式封装了 ...

  9. LESSON 5 - Markov Sources

    1.      Markov sources The state of the Markov chain is used to represent the “memory” of the source ...

  10. 【Android - 组件】之Activity生命周期的全面分析

    Activity是Android四大组件之首,其重要性不言而喻,Activity的生命周期更是我们了解Android工作机制的重中之重.我们一般将Activty的生命周期做两种情况下的理解,即正常情况 ...