zoukankan      html  css  js  c++  java
  • 《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,在用户存入数据库之前把电子邮件地址转换成全小写字母形式。

    补充

    其他的回调有:
    savevalidbefore_validationvalidateafter_validationbefore_savebefore_createcreateafter_createafter_saveafter_commit

    关于索引

    add_index :users, :email, unique: true
    

    上述代码调用了 Rails 中的 add_index 方法,为 users 表中的 email 列建立索引。索引本身并不能保证唯一性,所以还要指定 unique: true

    add_index :microposts, [:user_id, :created_at]
    

    我们把 user_idcreated_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
      
    • 获得一对“虚拟属性”,passwordpassword_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

    经过上述分析,我们计划按照下面的方式实现持久会话:

    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 参数,指定只应用在 editupdate 动作上。

    模板

    <%= 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_forform_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/tasksprojects/123/tasks/123

    Ajax

    只要把 form_for 改成 form_for…​, remote: true,Rails 就会自动使用 Ajax 处理表单。

    补充

    同理於超連結 link_to,按鈕 button_to 加上:remote => true參數也會變成 Ajax。

  • 相关阅读:
    HTML入门(一)
    WEB攻击手段及防御第2篇-SQL注入
    公司来了个新同事不会用 Lombok,还说我代码有问题!
    最流行的 RESTful API 要怎么设计?
    Spring Boot & Restful API 构建实战!
    分布式事务不理解?一次给你讲清楚!
    带着问题学 Kubernetes 架构!
    Linux 与 Unix 到底有啥区别和联系?
    Java虚拟机最多支持多少个线程?
    常用的 Git 命令,给你准备好了!
  • 原文地址:https://www.cnblogs.com/CodeCabin/p/4176803.html
Copyright © 2011-2022 走看看