《Ruby on Rails教程》学习笔记
本文是我在阅读 Ruby on Rails 教程的简体中文版时所做的摘录,以及学习时寻找的补充知识。补充知识主要来自于 Ruby on Rails 實戰聖經。
Asset Pipeline
在最新版 Rails 中,静态文件可以放在三个标准文件夹中,而且各有各的用途:
app/assets
:当前应用的资源文件;lib/assets
:开发团队自己开发的代码库使用的资源文件;vendor/assets
:第三方代码库使用的资源文件;
*= require_tree .
会把 app/assets/stylesheets
文件夹中的所有 CSS 文件(包含子文件夹中的文件)都引入应用的 CSS 。
*= require_self
会把 application.css
这个文件中的 CSS 也加载进来。
(预处理器引擎)按照扩展名的顺序从右向左处理
使用 Asset Pipeline,生产环境中应用所有的样式都会集中到一个 CSS 文件中(application.css
),所有 JavaScript 代码都会集中到一个 JavaScript 文件中(application.js
),而且还会压缩这些文件,删除不必要的空格,减小文件大小。
Active Record
关于回调
...“回调”(callback),在 Active Record 对象生命周期的特定时刻调用。现在,我们要使用的回调是 before_save
,在用户存入数据库之前把电子邮件地址转换成全小写字母形式。
补充
其他的回调有:
save
、valid
、before_validation
、validate
、after_validation
、before_save
、before_create
、create
、after_create
、after_save
、after_commit
关于索引
add_index :users, :email, unique: true
上述代码调用了 Rails 中的 add_index
方法,为 users
表中的 email
列建立索引。索引本身并不能保证唯一性,所以还要指定 unique: true
。
add_index :microposts, [:user_id, :created_at]
我们把 user_id
和 created_at
放在一个数组中,告诉 Rails 我们要创建的是“多键索引”(multiple key index),因此 Active Record 会同时使用这两个键。
关于顺序
为了得到特定的顺序,我们要在 default_scope
方法中指定 order
参数,按 created_at
列的值排序
default_scope -> { order(created_at: :desc) }
关于依赖属性
dependent: :destroy
的作用是在用户被删除的时候,把这个用户发布的微博也删除。
补充
:dependent
可以有三種不同的刪除方式,分別是::destroy
、:delete
、:nullify
关于自定义
has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
has_many :following, through: :active_relationships, source: :followed
补充
指定表名和主键:
class Category < ActiveRecord::Base
self.table_name = "your_table_name"
self.primary_key = "your_primary_key_name"
end
补充
书中多对多的关系自定义了很多名字,如果采用Rails默认命名,是下面的样子:
class Event < ActiveRecord::Base
has_many :event_groupships
has_many :groups, :through => :event_groupships
end
class EventGroupship < ActiveRecord::Base
belongs_to :event
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :event_groupships
has_many :events, :through => :event_groupships
end
测试
关于固件
固件的作用是为测试数据库提供示例数据
test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
创建了一个有效用户固件后,在测试中可以使用下面的方式获取这个用户:
user = users(:michael)
其中,users
对应固件文件 users.yml
的文件名,:michael
是代码清单 8.19 中定义的用户。
一个很好的测试用例
test "login with valid information" do
get login_path
post login_path, session: { email: @user.email, password: 'password' }
assert_redirected_to @user
follow_redirect!
assert_template 'users/show'
assert_select "a[href=?]", login_path, count: 0
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", user_path(@user)
end
end
在这段代码中,我们使用 assert_redirected_to @user
检查重定向的地址是否正确;使用 follow_redirect!
访问重定向的目标地址。还确认页面中有零个登录链接,从而确认登录链接消失了:
assert_select "a[href=?]", login_path, count: 0
count: 0
参数的目的是,告诉 assert_select
,我们期望页面中有零个匹配指定模式的链接。(代码清单 5.25中使用的是 count: 2
,指定必须有两个匹配模式的链接。)
安全
密码的实现
在模型中调用这个方法(has_secure_password
)后,会自动添加如下功能:
在数据库中的
password_digest
列存储安全的密码哈希值;
(通过下面迁移获得:)add_column :users, :password_digest, :string
获得一对“虚拟属性”,
password
和password_confirmation
,而且创建用户对象时会执行存在性验证和匹配验证;User.new(name: "Example User", email: "user@example.com", password: "foobar", password_confirmation: "foobar")
获得
authenticate
方法,如果密码正确,返回对应的用户对象,否则返回false
。user = User.find_by(email: "mhartl@example.com")
user.authenticate("not_the_right_password")
使用bcrypt
验证记忆令牌
BCrypt::Password.new(remember_digest).is_password?(remember_token)
关于健壮参数
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
@user = User.new(user_params)
必须只允许通过请求传入可安全编辑的属性。
admin
并不在允许使用的属性列表中。这样就可以避免用户取得网站的管理权。
Session和Cookie
经过上述分析,我们计划按照下面的方式实现持久会话:
- 生成随机字符串,当做记忆令牌;
- 把这个令牌存入浏览器的 cookie 中,并把过期时间设为未来的某个日期;
- 在数据库中存储令牌的摘要;
- 在浏览器的 cookie 中存储加密后的用户 ID;
- 如果 cookie 中有用户的 ID,就用这个 ID 在数据库中查找用户,并且检查 cookie 中的记忆令牌和数据库中的哈希摘要是否匹配。
Cookie的用法:
cookies[:remember_token] = { value: remember_token,
expires: 20.years.from_now.utc }
另一种简写:
cookies.permanent[:remember_token] = remember_token
加密Cookie:
cookies.signed[:user_id] = user.id
控制器
为了实现图 9.6 中的转向功能,我们要在用户控制器中使用“事前过滤器”。事前过滤器通过 before_action
方法设定,指定在某个动作运行前调用一个方法。
默认情况下,事前过滤器会应用于控制器中的所有动作,所以在上述代码中我们传入了 :only
参数,指定只应用在 edit
和 update
动作上。
模板
<%= render @users %>
Rails 会把 @users
当作一个 User
对象列表,传给 render
方法后,Rails 会自动遍历这个列表,然后使用局部视图 _user.html.erb
渲染每个对象。
关于表单
params
哈希中包含一个基于复选框状态的值。如果勾选了复选框,params[:session][:remember_me]
的值是 '1',否则是 '0'。
代码清单 9.2 和代码清单 7.13 都使用了相同的 form_for(@user)
来构建表单,那么 Rails 是怎么知道创建新用户要发送 POST
请求,而编辑用户时要发送 PATCH
请求的呢?这个问题的答案是,通过 Active Record 提供的 new_record?
方法检测用户是新创建的还是已经存在于数据库中
form_for(@user)
的作用是让表单向 /users
发起 POST
请求。对会话来说,我们需要指明资源的名字以及相应的 URL:
form_for(:session, url: login_path)
补充
form_for
和form_tag
的区别:
一種是對應到Model物件的新增、修改,我們會使用form_for
這個Helper。它的好處在於透過傳入Model物件,可以在修改的時候自動幫你將預設值帶入。例如我們已經在Part1使用過的event
表單:
<%= form_for @event do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
另一種是就是沒有對應Model的表單,我們使用form_tag
這個方法。例如:
<%= form_tag "/search" do %>
<%= text_field_tag :keyword %>
<%= submit_tag %>
<% end %>
和form_tag
有些類似,但是其中不需要傳Block變數f
,其中的欄位Helper需要多加_tag
結尾。不像form_for
的欄位名稱一定要是Model的屬性之一,在form_tag
之中的欄位名稱則完全不受限。
路由
resources :users do
member do
get :following, :followers
end
end
设定上述路由后,得到的 URL 地址类似 /users/1/following
和 /users/1/followers
这种形式。
除此之外,我们还可以使用 collection
方法,但 URL 中就没有用户 ID 了。
resources :users do
collection do
get :tigers
end
end
得到的 URL 是 /users/tigers
补充
另外还有这种使用方法:
resources :projects do
resources :tasks
end
得到的URL如projects/123/tasks
和projects/123/tasks/123
。
Ajax
只要把 form_for
改成 form_for…, remote: true
,Rails 就会自动使用 Ajax 处理表单。
补充
同理於超連結 link_to
,按鈕 button_to
加上:remote => true
參數也會變成 Ajax。
《Ruby on Rails教程》学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- 在Android中使用Protocol Buffers(中篇)
本文来自网易云社区. FlatBuffers 编码原理 FlatBuffers的Java库只提供了如下的4个类: ./com/google/flatbuffers/Constants.java ./c ...
- Cogs 1264. [NOIP2012] 开车旅行(70分 暴力)
1264. [NOIP2012] 开车旅行 ★★☆ 输入文件:drive.in 输出文件:drive.out 简单对比时间限制:2 s 内存限制:128 MB [题目描述] 小A 和小 ...
- AT2161 シャッフル / Shuffling
传送门 其实有一个显然的性质嘛:对于每个数,其实只要考虑它最右能被换到的位置就好了 然后设\(f[i][j]\)表示已经处理完了前\(i-1\)位,当前还有\(j\)个\(1\)可以自由支配(注意这里 ...
- 洛谷P4116 Qtree3
题目描述 给出\(N\)个点的一棵树(\(N-1\)条边),节点有白有黑,初始全为白 有两种操作: \(0\) \(i\) : 改变某点的颜色(原来是黑的变白,原来是白的变黑) \(1\) \(v\) ...
- 洛谷 P1551 亲戚(并查集模板)
嗯... 题目链接:https://www.luogu.org/problemnew/show/P1551 思路: 很显然地我们会发现,这是一道并查集的模板题,并且是考察了并查集中的”并“和”查“的操 ...
- 高并发web系统优化总结
1.背景 因为业务需要,搭建了一个系统,系统主要由两部分组成,web页面和数据库. mysql大概2万条数据,其中有一个字段是click_num点击次数,php页面会取点击次数最小的一条记录去进行操作 ...
- java——String、StringBuffer、StringBuilder、包装类、单双引号
String: String是一个特殊的类,被定义为final类型,为字符串常量,同样的字符串在常量池中不能重复. 但是由于使用关键字new创建新的字符串,java会在对中分配新的空间,这样即使字符串 ...
- 湖南省第十二届大学生计算机程序设计竞赛 problem A 2016
如果 a * b % 2016 == 0 如果a = 1 ,且 a * b % 2016 == 0 考虑一下a = 2017的时候 2017 * b = (2016 + 1) * b % 2016 = ...
- Unity Destroy和DestroyImmediate
Destroy(Object obj, float t = 0.0F); 删除一个游戏对象,组件或者资源. 物体obj现在被销毁或在指定了t时间过后销毁.如果obj是组件,它将从GameObject销 ...
- koa2 从入门到进阶之路 (五)
之前的文章我们介绍了一下 koa 中使用 ejs 模板及页面渲染,本篇文章我们来看一下 koa post提交数据及 koa-bodyparser中间件. 在前端页面中,不免会用到 form 表单和 p ...