本文是我在阅读 Ruby on Rails 教程的简体中文版时所作的摘录,以及学习时寻找的补充知识。补充知识主要来自于 Ruby on Rails 實戰聖經。css
在最新版 Rails 中,静态文件能够放在三个标准文件夹中,并且各有各的用途:html
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
),并且还会压缩这些文件,删除没必要要的空格,减少文件大小。安全
...“回调”(callback),在 Active Record 对象生命周期的特定时刻调用。如今,咱们要使用的回调是 before_save
,在用户存入数据库以前把电子邮件地址转换成全小写字母形式。cookie
其余的回调有:save
、valid
、before_validation
、validate
、after_validation
、before_save
、before_create
、create
、after_create
、after_save
、after_commit
session
add_index :users, :email, unique: true
上述代码调用了 Rails 中的 add_index
方法,为 users
表中的 email
列创建索引。索引自己并不能保证惟一性,因此还要指定 unique: true
。app
add_index :microposts, [:user_id, :created_at]
咱们把 user_id
和 created_at
放在一个数组中,告诉 Rails 咱们要建立的是“多键索引”(multiple key index),所以 Active Record 会同时使用这两个键。post
为了获得特定的顺序,咱们要在 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
并不在容许使用的属性列表中。这样就能够避免用户取得网站的管理权。
通过上述分析,咱们计划按照下面的方式实现持久会话:
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
。
只要把 form_for
改为 form_for…, remote: true
,Rails 就会自动使用 Ajax 处理表单。
同理於超連結 link_to
,按鈕 button_to
加上:remote => true
參數也會變成 Ajax。