ruby on rails 项目体验

rails new 项目名字   创建新项目

bin/rails server    启动服务器

bin/rails generate controller Welcome index  生成控制器和视图和一个路由

app/views/welcome/index.html.erb    在此替换html内容

在跟路由config/routes.rb    添加root 'welcome#index'配置路由信息,更换路由路径

在 Blog 应用中创建一个资源(resource)。资源是一个术语,表示一系列类似对象的集合,如文章、人或动物。资源中的项目可以被创建、读取、更新和删除,这些操作简称 CRUD(Create, Read, Update, Delete)。

Rails 提供了 resources 方法,用于声明标准的 REST 资源

# 添加资源   添加后会生成很多资源路由。resources :articles   

注意!资源添加后,路由没有对应的控制器,需要执行bin/rails generate controller Articles,并手动定义动作,只需要定义一个新方法就可以生成对应的控制器!!!

控制器实际上只是一个继承自 ApplicationController 的类,执行 CRUD 操作,在 Ruby 中,有 publicprivate 和 protected 三种方法,其中只有 public 方法才能作为控制器的动作。
 

ps:  执行 bin/rails routes 命令,可以看到所有标准 REST 动作都具有对应的路由。

第一个页面

当浏览器点击访问时,request.formats访问格式默认是text/html,因此 Rails 会查找 HTML 模板,request.variant 指明伺服的是何种物理设备,帮助 Rails 判断该使用哪个模板渲染响应。它的值是空的,因为没有为其提供信息。

提醒:模板的格式只能是 html,模板处理器只能是 erbbuilder 和 coffee 中的一个。:erb 是最常用的 HTML 模板处理器,:builder 是 XML 模板处理器,:coffee 模板处理器用 CoffeeScript 创建 JavaScript 模板。因为我们要创建 HTML 表单,所以应该使用能够在 HTML 中嵌入 Ruby 的 ERB 语言。

所以需要创建 articles/new.html.erb 文件,并把它放在应用的 app/views 文件夹中。

创建好了,就可以把改html视图在浏览器上渲染出来了。

第一个表单

Rails 中最常用的表单构建器是 form_for 辅助方法

调用 form_for 辅助方法时,需要为表单传递一个标识对象作为参数,这里是 :article 符号。这个符号告诉 form_for 辅助方法表单用于处理哪个对象。在 form_for 辅助方法的块中,f 表示 FormBuilder 对象,用于创建两个标签和两个文本字段,分别用于添加文章的标题和正文。最后在 f对象上调用 submit 方法来为表单创建提交按钮。

存在一点:表单 action 属性的值是 /articles/new,指向的是当前页面。

应该把表单指向其他 URL,为此可以使用 form_for 辅助方法的 :url 选项。在 Rails 中习惯用 create 动作来处理提交的表单,因此应该把表单指向这个动作。

修改 app/views/articles/new.html.erb 文件的 form_for 这一行,改为:

<%= form_for :article, url: articles_path do |f| %>

 articles_path 辅助方法传递给 :url 选项,articles_path 辅助方法告诉 Rails 把表单指向和 articles 前缀相关联的 URI 模式。默认情况下,表单会向这个路由发起 POST 请求。这个路由和当前控制器 ArticlesController 的 create动作相关联。

创建完后,在到对应的控制器添加create动作,表单就ok了~~ 表单提交后,其字段以参数形式传递给 Rails,然后就可以在控制器动作中引用这些参数,以执行特定任务。

def create
  render plain: params[:article].inspect
end

这里 render 方法接受了一个简单的散列(hash)作为参数,:plain 键的值是 params[:article].inspectparams 方法是代表表单提交的参数(或字段)的对象。params方法返回 ActionController::Parameters 对象,这个对象允许使用字符串或符号访问散列的键。这里我们只关注通过表单提交的参数。

请确保牢固掌握 params 方法,这个方法很常用。让我们看一个示例 URL:http://www.example.com/?username=dhh&[email protected]。在这个 URL 中,params[:username] 的值是“dhh”,params[:email] 的值是“[email protected]”。

创建模型:bin/rails generate model Article title:string text:text

执行迁移命令,生成迁移模型表:bin/rails db:migrate   该模型表默认在开发环境生成表,要想在其他环境中执行迁移,例如生产环境,就必须在调用命令时显式传递环境变量:bin/rails db:migrate RAILS_ENV=production

生成模型后可以去保存,调用create动作,如:

def create
  @article = Article.new(params[:article])
 
  @article.save
  redirect_to @article
end

为控制器参数设置白名单,以避免错误地批量赋值。:@article = Article.new(params.require(:article).permit(:title:text))

另外,除了批量赋值问题,为了禁止从外部调用这个方法,通常还要把它设置为 private

def create
  @article = Article.new(article_params)
 
  @article.save
  redirect_to @article
end
 
private
  def article_params
    params.require(:article).permit(:title, :text)
  end

动作提醒:标准的 CRUD 动作:indexshowneweditcreateupdate 和 destroy。你也可以按照自己的顺序放置这些动作,但要记住它们都是公开方法,如前文所述,必须放在私有方法之前才能正常工作。

class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])
  end
 
  def new
  end

 Article.find 来查找文章,并传入 params[:id] 以便从请求中获得 :id 参数。我们还使用实例变量(前缀为 @)保存对文章对象的引用。

在视图函数里:

<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

对应的实例属性.属性值可以将之前的属性用上。

所有表单页面视图/默认设置为首页

添加动作

def index
    @articles = Article.all
  end

添加视图html/index.html

添加链接

<%= link_to 'My Blog', controller: 'articles' %>

<%= link_to 'New article', new_article_path %>

<%= link_to 'Back', articles_path %>

以上方法都包含对各个视图的链接,利用该超链接将视图关系建立。

添加验证

目前模型文件简单到只有两行代码,ApplicationRecord 类继承自 ActiveRecord::Base 类。正是 ActiveRecord::Base 类为 Rails 模型提供了大量功能,包括基本的数据库 CRUD 操作(创建、读取、更新、删除)、数据验证,以及对复杂搜索的支持和关联多个模型的能力。

validates :title, presence: true,
                    length: { minimum: 5 }

添加的代码用于确保每篇文章都有标题,并且标题长度不少于 5 个字符。在 Rails 模型中可以验证多种条件,包括字段是否存在、字段是否唯一、字段的格式、关联对象是否存在,等等。

此时应该调整视图逻辑,当用户文章条件满足及不满足都要返回相应的视图:

def new
  @article = Article.new
end

if @article.save
    redirect_to @article
  else
    render 'new'

在 new 动作中创建了新的实例变量 @article,在 create 动作中,当 save 返回 false 时,我们用 render 代替了 redirect_to。使用 render 方法是为了把 @article 对象回传给 new 模板。这里渲染操作是在提交表单的这个请求中完成的,而 redirect_to 会告诉浏览器发起另一个请求。

修改完逻辑后,还要修改对应的视图页面(添加显示错误信息的代码:):

 <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2>
        <%= pluralize(@article.errors.count, "error"%> prohibited
        this article from being saved:
      </h2>
      <ul>
        <% @article.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

我们使用 @article.errors.any? 检查是否有错误,如果有错误就使用 @article.errors.full_messages 列出所有错误信息。

pluralize 是 Rails 提供的辅助方法,接受一个数字和一个字符串作为参数。如果数字比 1 大,字符串会被自动转换为复数形式。

在 ArticlesController 的new动作中添加 @article = Article.new 是因为如果不这样做,在视图中 @article 的值就会是 nil,这样在调用 @article.errors.any? 时就会抛出错误。

更新文章

在 ArticlesController 中添加 edit 动作,通常把这个动作放在 new 动作和 create 动作之间,接下来在视图中添加一个表单,这个表单类似于前文用于新建文章的表单。创建 app/views/articles/edit.html.erb 文件

method: :patch 选项告诉 Rails 使用 PATCH 方法提交表单。根据 REST 协议,PATCH 方法是更新资源时使用的 HTTP 方法。

接下来在 app/controllers/articles_controller.rb 文件中创建 update 动作

另外不用把所有属性都传递给 update 方法。例如,调用 @article.update(title: 'A new title') 时,Rails 只更新 title 属性而不修改其他属性。

最后,我们想在文章列表中显示指向 edit 动作的链接,接着在 app/views/articles/show.html.erb 模板中添加 Edit 链接,这样文章页面也有 Edit链接了。

使用局部视图去掉视图中的重复代码

按照约定,局部视图的文件名以下划线开头。除了第一行 form_for 的用法变了之外,其他代码都和之前一样。之所以能用这个更短、更简单的 form_for 声明来代替新建文章页面和编辑文章页面的两个表单,是因为 @article 是一个资源,对应于一套 REST 式路由,Rails 能够推断出应该使用哪个地址和方法。更新 相关视图,以使用新建的局部视图。把文件内容替换。

删除文章

删除资源的路由应该使用 delete 路由方法。如果在删除资源时仍然使用 get 路由,就可能给那些设计恶意地址的人提供可乘之机:

delete 方法来删除资源,对应的路由会映射到 app/controllers/articles_controller.rb 文件中的 destroy 动作。

destroy 动作是控制器中的最后一个 CRUD 动作,和其他公共 CRUD 动作一样,这个动作应该放在 private 或 protected 方法之前。

注意,我们不需要为 destroy 动作添加视图,因为完成操作后它会重定向到 index 动作。

最后,在 index 动作的模板(app/views/articles/index.html.erb)中加上“Destroy”链接,这样就大功告成了:

link_to 辅助方法生成“Destroy”链接的用法有点不同,其中第二个参数是具名路由(named route),还有一些选项作为其他参数。method: :delete 和 data: { confirm: 'Are you sure?' } 选项用于设置链接的 HTML5 属性,这样点击链接后 Rails 会先向用户显示一个确认对话框,然后用 delete 方法发起请求。这些操作是通过 JavaScript 脚本 rails-ujs 实现的,这个脚本在生成应用骨架时已经被自动包含在了应用的布局中(app/views/layouts/application.html.erb)。如果没有这个脚本,确认对话框就无法显示。

添加第二个模型(用于处理文章评论)

 生成模型    bin/rails generate model Comment commenter:string body:text article:references

references 关键字是一种特殊的模型数据类型,用于在数据表中新建字段。这个字段以提供的模型名加上 _id 后缀作为字段名,保存整数值。

上面的命令会生成 4 个文件:

文件 用途
db/migrate/20140120201010_create_comments.rb 用于在数据库中创建 comments 表的迁移文件(你的文件名会包含不同的时间戳)
app/models/comment.rb Comment 模型文件
test/models/comment_test.rb Comment 模型的测试文件
test/fixtures/comments.yml 用于测试的示例评论

belongs_to :article   

这行代码用于建立 Active Record 关联。声明每一条评论都属于某一篇文章,模型关联的另一端:article.rb,添加has_many :comments.

例如,如果 @article 实例变量表示一篇文章,就可以使用 @article.comments 以数组形式取回这篇文章的所有评论。

t.references 这行代码创建 article_id 整数字段,为这个字段建立索引,并建立指向 articles 表的 id 字段的外键约束。

数据库生成表命令:bin/rails db:migrate

为评论添加路由

resources :articles do
  resources :comments
end

上面的代码在 articles 资源中创建 comments 资源,这种方式被称为嵌套资源。这是表明文章和评论之间层级关系的另一种方式。

生成控制器

bin/rails generate controller Comments

上面的命令会创建 5 个文件和一个空文件夹:

文件/文件夹 用途
app/controllers/comments_controller.rb Comments 控制器文件
app/views/comments/ 控制器的视图保存在这里
test/controllers/comments_controller_test.rb 控制器的测试文件
app/helpers/comments_helper.rb 视图辅助方法文件
app/assets/javascripts/comments.coffee 控制器的 CoffeeScript 文件
app/assets/stylesheets/comments.scss 控制器的样式表文件

修改显示文章的模板(app/views/articles/show.html.erb),添加发表评论的功能

<h2>Add a comment:</h2>
<%= form_for([@article@article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

调用 CommentsController 的 create 动作来发表评论。这里 form_for 辅助方法以数组为参数,会创建嵌套路由,例如 /articles/1/comments

接下来在 app/controllers/comments_controller.rb 文件中添加 create 动作:

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end
 
  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end

上面的代码比 Articles 控制器的代码复杂得多,这是嵌套带来的副作用。对于每一个发表评论的请求,都必须记录这条评论属于哪篇文章,因此需要在 Article 模型上调用 find 方法来获取文章对象。

此外,上面的代码还利用了关联特有的方法,在 @article.comments 上调用 create 方法来创建和保存评论,同时自动把评论和对应的文章关联起来。

添加评论后,我们使用 article_path(@article) 辅助方法把用户带回原来的文章页面。如前文所述,这里调用了 ArticlesController 的 show 动作来渲染 show.html.erb 模板,因此需要修改 app/views/articles/show.html.erb 文件来显示评论:

渲染局部视图集合

创建评论的局部视图,把显示文章评论的代码抽出来

<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>
 
<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>

修改 app/views/articles/show.html.erb ,这样对于 @article.comments 集合中的每条评论,都会渲染 app/views/comments/_comment.html.erb 文件中的局部视图。render 方法会遍历 @article.comments 集合,把每条评论赋值给局部视图中的同名局部变量,也就是这里的 comment变量。

渲染局部视图表单

把添加评论的代码也移到局部视图中。创建 app/views/comments/_form.html.erb 文件,添加下面的代码

<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

修改 app/views/articles/show.html.erb 文件

上面的代码中第二个 render 方法的参数就是我们刚刚定义的 comments/form 局部视图。Rails 很智能,能够发现字符串中的斜线,并意识到我们想渲染 app/views/comments 文件夹中的 _form.html.erb 文件。

@article 是实例变量,因此在所有局部视图中都可以使用。

 删除评论

在视图中添加一个链接,并在 CommentsController 中添加 destroy 动作。

点击“Destroy Comment”链接后,会向 CommentsController 发起 DELETE /articles/:article_id/comments/:id 请求,这个请求将用于删除指定评论。下面在控制器(app/controllers/comments_controller.rb)中添加 destroy 动作:

destroy 动作首先找到指定文章,然后在 @article.comments 集合中找到指定评论,接着从数据库删除这条评论,最后重定向到显示文章的页面。

删除关联对象

如果要删除一篇文章,文章的相关评论也需要删除,否则这些评论还会占用数据库空间。在 Rails 中可以使用关联的 dependent 选项来完成这一工作。像下面这样修改 app/models/article.rb 文件中的 Article 模型:

class Article < ApplicationRecord
  has_many :comments, dependent: :destroy
  validates :title, presence: true,
                    length: { minimum: 5 }
end

如果要删除一篇文章,文章的相关评论也需要删除,否则这些评论还会占用数据库空间。在 Rails 中可以使用关联的 dependent 选项来完成这一工作。像下面这样修改 app/models/article.rb 文件中的 Article 模型:

class Article < ApplicationRecord
  has_many :comments, dependent: :destroy
  validates :title, presence: true,
                    length: { minimum: 5 }

安全

我们需要一种方法来禁止未认证用户访问 ArticlesController 的动作。这里我们可以使用 Rails 的 http_basic_authenticate_with 方法,通过这个方法的认证后才能访问所请求的动作。

要使用这个身份验证系统,可以在 app/controllers/articles_controller 文件中的 ArticlesController 的顶部进行指定。这里除了 index 和 show 动作,其他动作都要通过身份验证才能访问,为此要像下面这样添加代码:

class ArticlesController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
 
  def index
    @articles = Article.all
  end
 
  # 为了行文简洁,省略以下内容

同时只有通过身份验证的用户才能删除评论,为此要在 CommentsControllerapp/controllers/comments_controller.rb)中像下面这样添加代码:

class CommentsController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
 
  def create
    @article = Article.find(params[:article_id])
    # ...
  end
 
  # 为了行文简洁,省略以下内容

猜你喜欢

转载自blog.csdn.net/qq_42672332/article/details/85712551