跳至主要內容

Rails

酷风大约 8 分钟

Rails

  • Rails 是用 Ruby 编程语言编写的 Web 应用程序开发框架。

入门

  • gem install rails
  • rails --version
  • sqlite3 --version
  • rails new hello-rails
  • 启动 bin/rails server
  • 一键生成:bin/rails generate controller HelloRails index
    • HelloRails 自动转下划线风格分割 hello_rails
    • 控制器:hello_rails_controller.rb
    • 路由:hello_rails/index
    • 视图:app/views/hello_rails/index.html.erb
  • 配置主页 / ,设置路由 vi config/routes.rb
    • 使用 # 符号
    • hello_rails/index > 'hello_rails#index'
# config/routes.rb
Rails.application.routes.draw do
  get 'hello_rails/index'
  root 'hello_rails#index'
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

说明


bin/rails generate controller HelloRails index
      create  app/controllers/hello_rails_controller.rb
       route  get 'hello_rails/index'
      invoke  erb
      create    app/views/hello_rails
      create    app/views/hello_rails/index.html.erb
      invoke  test_unit
      create    test/controllers/hello_rails_controller_test.rb
      invoke  helper
      create    app/helpers/hello_rails_helper.rb
      invoke    test_unit

  • 目录介绍

bundler

  • 安装依赖
    • 依据 Gemfile 文件 自动安装依赖
    • bundle install
  • Gemfile 示例

source 指定源
gem 安装的包及版本

source 'https://rubygems.org'
gem 'nokogiri'

入门实践

  • 举例 对用户管理,用户CURD
  1. 创建控制器
  2. 创建动作
  3. 创建视图
    1. 参数处理
  4. 创建模型:生成迁移文件
  5. 运行迁移:生成表
  6. 保存数据
  7. 显示数据
  8. 视图链接
  9. 表单验证
    1. 错误回显
  10. 视图布局,局部代码,代码复用,如相同form表单
  11. 删除数据
  12. 模型关联
    1. 级连操作
  13. 安全,如安全认证

资源 resources

  • Rails 提供了 resources 方法,用于声明标准的 REST 资源。
  • 如声明 用户 的资源 resources :users
  • config/routes.rb
Rails.application.routes.draw do
  get 'welcome/index'
 
  resources :users
 
  root 'welcome#index'
end

资源路由

  • Rails 能够推导出 如资源 users 的路由
  • 执行命令 bin/rails routes

路由 Routes

  • 命令: 列出所有路由 bin/rails routes
  • 也会列出 声明资源的路由 推导出资源路由 见 资源路由

控制器 Controller

  • 控制器实际上只是一个继承自 ApplicationController 的类。

  • 自动创建控制器

  • 命令: bin/rails generate controller Users

  • app/controllers/users_controller.rb

class UsersController < ApplicationController
end

动作 Action

  • 在控制器中手动定义动作,只需要定义一个新方法。
  • 如定义创建用户页面
class UsersController < ApplicationController

  def new
  end

end

参数处理

  • 如创建表单,定义创建action ,获取参数
    • render 方法接受了一个简单的散列(hash)作为参数
    • :plain 键的值是 params[:user].inspect。
      • params 方法是代表表单提交的参数(或字段)的对象。
      • params 方法返回 ActionController::Parameters 对象,这个对象允许使用字符串或符号访问散列的键。
  def create
    render plain: params[:user].inspect
  end
  • 查看该动作的响应信息
    • #<ActionController::Parameters {"username"=>"11", "password"=>"11", "user_desc"=>"11"} permitted: false>
  • render plain: params[:user][:username].inspect
    • render plain: params[:user][:username].inspect

保存数据

  • 在创建action中保存数据
    • Rails 模型可以用相应的属性初始化,它们会自动映射到对应的数据库字段。
      • @user = User.new(params[:user])
    • @article.save 负责把模型保存到数据库。最后把页面重定向
    • User.new 中 User 为模型
  def create
    @user = User.new(params[:user])
    @user.save
    redirect_to @user
  end

健壮参数

  • Rails 提供了多种安全特性来帮助我们编写安全的应用,健壮参数就是一种安全特性。

  • 如进行上述保存数据,操作会报错

  • ActiveModel::ForbiddenAttributesError in UsersController#create

    • 要求我们明确地告诉 Rails 哪些参数允许在控制器动作中使用。
    • 避免有人对服务器发起了一个精心设计的请求,看起来就像提交了一篇新文章,但同时包含了能够破坏应用完整性的额外字段和值,会怎么样?这些恶意数据会批量赋值给模型,然后和正常数据一起进入数据库,这样就有可能破坏我们的应用或者造成更大损失。

  • @user = User.new(params.require([:user]).permit(:username, :nickname, :password, :user_desc))
  • 所以我们只能为控制器参数设置白名单,以避免错误地批量赋值。
  • 我们想在 create 动作中合法使用 需要的 参数,为此需要使用 require 和 permit 方法。

方法抽象

  • 如上述 健壮参数只获取我们需要的字段,将该步骤抽象为一个方法 user_params
  • private: 禁止从外部调用此方法
  def create
    @user = User.new(user_params)
    @user.save
    redirect_to @user
  end

  private
    def user_params
      params.require(:user).permit(:username, :nickname, :password, :user_desc)
    end

数据展示

  • @user @对象 :表示 返回一个对象

  • @user = User.new 返回一个空对象

  • 通过 bin/rails routes 可以看到,users资源 的展示动作为show 见资源路由

    • 控制器创建 show, 视图 创建 users/show.html.erb
  • 查询数据 ID 为 1 的

  • /users/1

  def show
    @user = User.find(params[:id])
  end

  • 展示所有用户
  • /users ,查看对应动作 bin/rails routes:index
  • 视图 index.html.erb
  def index
    @users = User.all
  end

render vs redirect_to

  • 注意在 create 动作中,当 save 返回 false 时,我们用 render 代替了 redirect_to。
    • render 方法是为了把 @article 对象回传给 new 模板。这里渲染操作是在提交表单的这个请求中完成的,
    • redirect_to 会告诉浏览器发起另一个请求。
  • 数据验证部分应用

视图模版 view template

  • 当在路由中声明了 users 资源,创建了控制器并定义了 new 动作

    • 此时路由会指向 new 的一个视图模版
    • 报错信息:UsersController#new is missing a template for request formats: text/html
    • app/controllers/users_controller.rb should have a corresponding view template in a file named app/views/users/new.html.erb.
  • app/views/users/new.html.erb

    • 第一个扩展名是模板格式 html
    • 第二个扩展名是模板处理器
      • erb 是最常用的 HTML 模板处理器
      • builder 是 XML 模板处理器
      • coffee 模板处理器用 CoffeeScript 创建 JavaScript 模板

表单构造器

  • 参考 form_for 的文档open in new window
  • 在模板中创建表单,可以使用表单构建器。
    • Rails 中最常用的表单构建器是 form_for 辅助方法。
  • 用户表单
    • 需要为表单传递一个标识对象作为参数
      • 第一个参数为对象
        • :user 表单用于处理哪个对象
        • f 表示 FormBuilder 对象
          • f 对象上调用 submit 方法来为表单创建提交按钮
        • 默认表单提交的地址为 /users/new ,但这个路由是进入到new页面的
      • 第二个参数,url: users_path
        • 告诉 Rails 把表单指向和 users 前缀相关联的 URI 模式
          • 此时提交表单路由会指向create 见资源路由
          • 控制器定义 动作 create ,否则报错:AbstractController::ActionNotFound (The action 'create' could not be found for UsersController):
<%= form_for :user, url: users_path do |f| %>
  <p>
    <%= f.label :用户名 %><br>
    <%= f.text_field :username %>
  </p>

  <p>
    <%= f.label :用户密码 %><br>
    <%= f.password_field :password %>
  </p>

  <p>
    <%= f.label :用户描述 %><br>
    <%= f.text_area :user_desc %>
  </p>

  <p>
    <%= f.submit :创建用户%>
  </p>
<% end %>

添加链接

  • link_to: Rails 内置的视图辅助方法之一,用于创建基于链接文本和地址的超链接。
  • <%= link_to '查看用户列表', controller: 'users' %>
  • <%= link_to '创建用户', new_user_path %>

链接到当前控制器的动作时不需要指定 :controller 选项,因为 Rails 默认使用当前控制器。

错误回显

  def new
    @user = User.new
  end
  
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render :new, status: :unprocessable_entity
    end
  end
  • 视图错误字段回显
    • pluralize
      • Rails 提供的辅助方法
      • 接受一个数字和一个字符串作为参数。如果数字比 1 大,字符串会被自动转换为复数形式。
      • 发现 <%= pluralize(@user.errors.count, "error") %> ,创建异常。
        • 发现 2 errors ,创建异常。
        • 发现 1 error ,创建异常。
        • 中文 会加s: 发现 2 错误s ,创建异常。
<%= form_for :user, url: users_path do |f| %>

  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2>
        发现 <%= pluralize(@user.errors.count, "error") %> ,创建异常。
      </h2>
      <ul>
        <% @user.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <p>
    <%= f.label :登录用户名 %><br>
    <%= f.text_field :username %>
    <% @user.errors.full_messages_for(:username).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </p>

Rails 布局和视图渲染

  • 如编辑和新建用户页面,都使用一致的表单
  • 抽取form重复代码
    • 创建 app/views/users/_form.html.erb
    • 其他页面引用 <%= render 'form' %>

对象(资源)模型

  • 创建如 用户 对象 模型
    • bin/rails generate model User username:string nickname:string password:string user_desc:text
  • active_record
    • Active Record 很智能,能自动把数据表的字段名映射到模型属性上,因此无需在 Rails 模型中声明属性,让 Active Record 自动完成即可。
      invoke  active_record
      create    db/migrate/20231210064012_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml

迁移 Active Record

  • 迁移是用于简化创建和修改数据库表操作的 Ruby 类;
    • Rails 使用 rake 命令运行迁移,并且在迁移作用于数据库之后还可以撤销迁移操作。
    • 迁移的文件名包含了时间戳,以确保迁移按照创建时间顺序运行。
    • db/migrate/YYYYMMDDHHMMSS_create_users.rb

  • bin/rails generate model 命令会在 db/migrate 文件夹中生成数据库迁移文件。
    • db/migrate/20231210064012_create_users.rb
class CreateUsers < ActiveRecord::Migration[7.1]
  def change
    create_table :users do |t|
      t.string :username
      t.string :nickname
      t.string :password
      t.text :user_desc

      t.timestamps
    end
  end
end

  • 生成迁移文件后,执行 bin/rails db:migrate
  • 生成用户表
    • 默认情况下我们是在开发环境中工作
    • 命令应用于 config/database.yml 文件中 development 部分定义的的数据库。
      • 也可显示指定环境 bin/rails db:migrate RAILS_ENV=production
 bin/rails db:migrate
== 20231210064012 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0044s
== 20231210064012 CreateUsers: migrated (0.0045s) =============================

数据验证

  • 模型文件简单到只有两行代码
class User < ApplicationRecord
end
  • User 继承自 ApplicationRecord 类
    • ApplicationRecord 继承自 ActiveRecord::Base 类
    • Base 类为 Rails 模型提供了大量功能
      • 基本的数据库 CRUD 操作(创建、读取、更新、删除)、数据验证,以及对复杂搜索的支持和关联多个模型的能力。
  • 对用户名进行验证
  • User,用户名必填,至少5位
class User < ApplicationRecord
  validates :username, presence: true, length: {minimum: 5}
end
  • 判断处理
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

对象操作

  • 创建空对象 User.new
  • 根据参数提交对象 User.new(user_params)
    • 保存对象 @user.save
  • 查找对象 @user = Article.find(params[:id])
    • 删除对象 * @user.destroy
  • 查找所有对象
    • User.all

模型关联

  • 生成日志模型关联用户
    • bin/rails generate model Log log_key:string log_content:text user:references
    • 表示日志输入用户
    • belongs_to
  • 自动生成关联表 bin/rails db:migrate,参考 迁移 Active Record
  • 可以在User中加 关联关系 has_many
    • 级连删除:dependent: :destroy

安全

基本身份验证

  • http_basic_authenticate_with

  • UsersController

    • 动作认证,除了index 和 show
    • http_basic_authenticate_with name: "root", password: "123456", except: [:index, :show]
  • 参考官方文档Active Record 数据验证open in new window