《RubyonRails教程》学习笔记

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

《RubyonRails教程》学习笔记
本⽂是我在阅读的时所做的摘录,以及学习时寻找的补充知识。

补充知识主要来⾃于。

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@
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@", password: "foobar", password_confirmation: "foobar")
获得authenticate⽅法,如果密码正确,返回对应的⽤户对象,否则返回false。

user = User.find_by(email: "mhartl@")
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
经过上述分析,我们计划按照下⾯的⽅式实现持久会话:
1. ⽣成随机字符串,当做记忆令牌;
2. 把这个令牌存⼊浏览器的 cookie 中,并把过期时间设为未来的某个⽇期;
3. 在数据库中存储令牌的摘要;
4. 在浏览器的 cookie 中存储加密后的⽤户 ID;
5. 如果 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。

相关文档
最新文档