介绍
Ruby on Rails 是一个用 Ruby 编写的 Web 应用程序框架,它为开发人员提供了一种自以为是的应用程序开发方法。 使用 Rails 可为开发人员提供:
- 处理路由、有状态数据和资产管理等事务的约定。
- model-view-controller (MCV) 架构模式的坚实基础,它将位于模型中的应用程序逻辑与应用程序信息的表示和路由分开。
当您增加 Rails 应用程序的复杂性时,您可能会使用多个模型,这些模型代表您的应用程序的业务逻辑和与数据库的接口。 添加相关模型意味着在它们之间建立有意义的关系,然后影响信息如何通过应用程序的控制器传递,以及如何捕获信息并通过视图呈现给用户。
在本教程中,您将构建一个现有的 Rails 应用程序,该应用程序向用户提供有关鲨鱼的事实。 此应用程序已经有一个处理鲨鱼数据的模型,但是您将为有关单个鲨鱼的帖子添加一个嵌套资源。 这将允许用户对单个鲨鱼建立更广泛的想法和意见。
先决条件
要遵循本教程,您将需要:
- 运行 Ubuntu 18.04 的本地机器或开发服务器。 您的开发机器应该有一个具有管理权限的非 root 用户和一个配置了
ufw
的防火墙。 有关如何设置的说明,请参阅我们的 Initial Server Setup with Ubuntu 18.04 教程。 - Node.js 和 npm 安装在本地机器或开发服务器上。 本教程使用 Node.js 版本 10.16.3 和 npm 版本 6.9.0。 有关在 Ubuntu 18.04 上安装 Node.js 和 npm 的指导,请按照 如何在 Ubuntu 18.04 上安装 Node.js 的“使用 PPA 安装”部分中的说明进行操作。
- Ruby、rbenv 和 Rails 安装在本地计算机或开发服务器上,遵循 如何在 Ubuntu 18.04 上使用 rbenv 安装 Ruby on Rails 中的步骤 1-4。 本教程使用 Ruby 2.5.1、rbenv 1.1.2 和 Rails 5.2.3。
- 按照 How To Build a Ruby on Rails Application 中的说明安装 SQLite,并创建了一个基本的鲨鱼信息应用程序。
第 1 步——搭建嵌套模型的脚手架
我们的应用程序将利用 Active Record associations 来建立 Shark
和 Post
模型之间的关系:帖子将属于特定的鲨鱼,每个鲨鱼可以有多个帖子. 因此,我们的 Shark
和 Post
模型将通过 belongs_to 和 has_many 关联相关联。
以这种方式构建应用程序的第一步是创建一个 Post
模型和相关资源。 为此,我们可以使用 rails generate scaffold
命令,它会给我们一个模型,一个 数据库迁移 来改变数据库模式,一个控制器,一套完整的视图来管理标准 [ X187X]创建、读取、更新和删除 (CRUD) 操作,以及用于部分、帮助程序和测试的模板。 我们需要修改这些资源,但是使用 scaffold
命令会节省我们一些时间和精力,因为它会生成一个我们可以用作起点的结构。
首先,确保您位于您在先决条件中创建的 Rails 项目的 sharkapp
目录中:
cd sharkapp
使用以下命令创建您的 Post
资源:
rails generate scaffold Post body:text shark:references
对于 body:text
,我们告诉 Rails 在 posts
数据库表中包含一个 body
字段——该表映射到 Post
模型。 我们还包括 :references
关键字,它在 Shark
和 Post
模型之间建立关联。 具体来说,这将确保将表示 sharks
数据库中每个鲨鱼条目的 外键 添加到 posts
数据库中。
运行命令后,您将看到确认 Rails 为应用程序生成的资源的输出。 在继续之前,您可以检查数据库迁移文件以查看模型和数据库表之间现在存在的关系。 使用以下命令查看文件的内容,确保将您自己的迁移文件上的时间戳替换为此处显示的内容:
cat db/migrate/20190805132506_create_posts.rb
您将看到以下输出:
Outputclass CreatePosts < ActiveRecord::Migration[5.2] def change create_table :posts do |t| t.text :body t.references :shark, foreign_key: true t.timestamps end end end
如您所见,该表包含一个鲨鱼外键列。 该密钥将采用 model_name_id
的形式——在我们的例子中是 shark_id
。
Rails 也在其他地方建立了模型之间的关系。 使用以下命令查看新生成的 Post
模型:
cat app/models/post.rb
Outputclass Post < ApplicationRecord belongs_to :shark end
belongs_to
关联建立模型之间的关系,其中声明模型的单个实例属于命名模型的单个实例。 在我们的应用程序中,这意味着单个帖子属于单个鲨鱼。
除了设置这种关系之外,rails generate scaffold
命令还为帖子创建路由和视图,就像在 How To Build a Ruby on Rails 的 Step 3 中为我们的鲨鱼资源所做的那样应用。
这是一个有用的开始,但我们需要配置一些额外的路由并巩固 Shark
模型的 Active Record 关联,以便我们的模型和路由之间的关系按预期工作。
第 2 步 — 为父模型指定嵌套路由和关联
Rails 已经在我们的 Post
模型中设置了 belongs_to
关联,这要归功于 rails generate scaffold
命令中的 :references
关键字,但是为了使这种关系发挥作用正确地,我们还需要在我们的 Shark
模型中指定一个 has_many
关联。 我们还需要更改 Rails 提供给我们的默认路由,以使 post 资源成为 Shark 资源的子资源。
要将 has_many
关联添加到 Shark
模型,请使用 nano
或您喜欢的编辑器打开 app/models/shark.rb
:
nano app/models/shark.rb
将以下行添加到文件中以建立鲨鱼和帖子之间的关系:
~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord has_many :posts validates :name, presence: true, uniqueness: true validates :facts, presence: true end
这里值得考虑的一件事是,一旦删除了特定的鲨鱼,帖子会发生什么。 我们可能不希望与已删除鲨鱼相关的帖子保留在数据库中。 为了确保在删除该鲨鱼时删除与给定鲨鱼相关的任何帖子,我们可以在关联中包含 dependent
选项。
将以下代码添加到文件中,以确保对给定鲨鱼的 destroy
操作删除任何关联的帖子:
~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord has_many :posts , dependent: :destroy validates :name, presence: true, uniqueness: true validates :facts, presence: true end
完成这些更改后,保存并关闭文件。 如果您正在使用 nano
,您可以按 CTRL+X
、Y
,然后按 ENTER
来执行此操作。
接下来,打开你的 config/routes.rb
文件来修改你的资源路由之间的关系:
nano config/routes.rb
目前,该文件如下所示:
~/sharkapp/config/routes.rb
Rails.application.routes.draw do resources :posts resources :sharks root 'sharks#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
当前代码在我们的路线之间建立了独立的关系,当我们想要表达的是鲨鱼及其相关帖子之间的依赖关系。
让我们更新我们的路由声明,使 :sharks
成为 :posts
的父级。 将文件中的代码更新为如下所示:
~/sharkapp/config/routes.rb
Rails.application.routes.draw do resources :sharks do resources :posts end root 'sharks#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
完成编辑后保存并关闭文件。
完成这些更改后,您可以继续更新 posts
控制器。
第 3 步 — 更新 Posts 控制器
我们的模型之间的关联为我们提供了可以用来创建与特定鲨鱼相关联的新帖子实例的方法。 要使用这些方法,我们需要将它们添加到我们的帖子控制器中。
打开帖子控制器文件:
nano app/controllers/posts_controller.rb
目前,该文件如下所示:
~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update, :destroy] # GET /posts # GET /posts.json def index @posts = Post.all end # GET /posts/1 # GET /posts/1.json def show end # GET /posts/new def new @post = Post.new end # GET /posts/1/edit def edit end # POST /posts # POST /posts.json def create @post = Post.new(post_params) respond_to do |format| if @post.save format.html { redirect_to @post, notice: 'Post was successfully created.' } format.json { render :show, status: :created, location: @post } else format.html { render :new } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # PATCH/PUT /posts/1 # PATCH/PUT /posts/1.json def update respond_to do |format| if @post.update(post_params) format.html { redirect_to @post, notice: 'Post was successfully updated.' } format.json { render :show, status: :ok, location: @post } else format.html { render :edit } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # DELETE /posts/1 # DELETE /posts/1.json def destroy @post.destroy respond_to do |format| format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_post @post = Post.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def post_params params.require(:post).permit(:body, :shark_id) end end
与我们的鲨鱼控制器一样,此控制器的方法与关联的 Post
类的实例一起使用。 例如,new
方法创建了 Post
类的新实例,index
方法抓取了该类的所有实例,set_post
方法使用find
和 params
通过 id
选择特定帖子。 但是,如果我们希望我们的 post 实例与特定的鲨鱼实例相关联,那么我们将需要修改此代码,因为 Post
类当前作为独立实体运行。
我们的修改将利用两件事:
- 当我们将
belongs_to
和has_many
关联添加到我们的模型时,我们可以使用这些方法。 具体来说,由于我们在Shark
模型中定义的has_many
关联,我们现在可以访问 构建方法 。 此方法将允许我们使用posts
数据库中存在的shark_id
外键创建与特定鲨鱼对象关联的帖子对象的集合。 - 当我们创建嵌套的
posts
路由时可用的路由和路由助手。 有关在资源之间创建嵌套关系时可用的示例路由的完整列表,请参阅 Rails 文档。 现在,我们只要知道对于每条特定的鲨鱼——比如sharks/1
——都会有一条与该鲨鱼相关的帖子的关联路线:sharks/1/posts
。 还会有路由助手,如shark_posts_path(@shark)
和edit_sharks_posts_path(@shark)
引用这些嵌套路由。
在该文件中,我们将首先编写一个方法 get_shark
,它将在控制器中的每个操作之前运行。 此方法将通过 shark_id
查找鲨鱼实例来创建本地 @shark
实例变量。 有了文件中的这个变量,我们就可以在其他方法中将帖子与特定的鲨鱼相关联。
在文件底部的其他 private
方法之上,添加以下方法:
~/sharkapp/controllers/posts_controller.rb
. . . private def get_shark @shark = Shark.find(params[:shark_id]) end # Use callbacks to share common setup or constraints between actions. . . .
接下来,将相应的过滤器添加到文件的 top 中,在现有过滤器之前:
~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController before_action :get_shark
这将确保 get_shark
在文件中定义的每个操作之前运行。
接下来,您可以使用这个 @shark
实例来重写 index
方法。 我们希望此方法返回与特定鲨鱼实例关联的所有 post 实例,而不是获取 Post
类的所有实例。
将 index
方法修改为如下所示:
~/sharkapp/controllers/posts_controller.rb
. . . def index @posts = @shark.posts end . . .
new
方法需要类似的修改,因为我们希望一个新的帖子实例与特定的鲨鱼相关联。 为此,我们可以使用 build
方法以及本地 @shark
实例变量。
将 new
方法更改为如下所示:
~/sharkapp/controllers/posts_controller.rb
. . . def new @post = @shark.posts.build end . . .
此方法创建一个 post 对象,该对象与 get_shark
方法中的特定鲨鱼实例相关联。
接下来,我们将讨论与 new
最密切相关的方法:create
。 create
方法做了两件事:它使用用户在 new
表单中输入的参数构建一个新的帖子实例,如果没有错误,它会保存该实例并使用路由助手将用户重定向到他们可以看到新帖子的地方。 如果出现错误,它会再次呈现 new
模板。
将 create
方法更新为如下所示:
~/sharkapp/controllers/posts_controller.rb
def create @post = @shark.posts.build(post_params) respond_to do |format| if @post.save format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' } format.json { render :show, status: :created, location: @post } else format.html { render :new } format.json { render json: @post.errors, status: :unprocessable_entity } end end end
接下来看一下update
方法。 此方法使用 @post
实例变量,该变量未在方法本身中显式设置。 这个变量从何而来?
查看文件顶部的过滤器。 第二个自动生成的 before_action
过滤器提供了答案:
~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController before_action :get_shark before_action :set_post, only: [:show, :edit, :update, :destroy] . . .
update
方法(如 show
、edit
和 destroy
)从 set_post
方法中获取 @post
变量. 该方法与我们的其他 private
方法一起列在 get_shark
方法下,目前如下所示:
~/sharkapp/controllers/posts_controller.rb
. . . private . . . def set_post @post = Post.find(params[:id]) end . . .
为了与我们在文件中其他地方使用的方法保持一致,我们需要修改此方法,以便 @post
引用与特定帖子相关联的帖子的 集合 中的特定实例鲨鱼。 请牢记 build
方法 - 由于我们的模型之间的关联,以及通过这些关联对我们可用的方法(如 build
),我们的每个帖子实例都是与特定鲨鱼相关联的对象集合的一部分。 因此,在查询特定帖子时,我们将查询与特定鲨鱼关联的帖子集合是有道理的。
将 set_post
更新为如下所示:
~/sharkapp/controllers/posts_controller.rb
. . . private . . . def set_post @post = @shark.posts.find(params[:id]) end . . .
我们不是通过 id
查找整个 Post
类的特定实例,而是在与特定鲨鱼相关的帖子集合中搜索匹配的 id
。
更新该方法后,我们可以查看 update
和 destroy
方法。
update
方法利用 set_post
中的 @post
实例变量,并与用户在 [ 中输入的 post_params
一起使用X150X] 形式。 在成功的情况下,我们希望 Rails 将用户返回到与特定鲨鱼相关的帖子的 index
视图。 如果出现错误,Rails 将再次渲染 edit
模板。
在这种情况下,我们需要做的唯一更改是对 redirect_to
语句进行处理,以处理成功的更新。 更新它以重定向到 shark_post_path(@shark)
,这将重定向到所选鲨鱼帖子的 index
视图:
~/sharkapp/controllers/posts_controller.rb
. . . def update respond_to do |format| if @post.update(post_params) format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' } format.json { render :show, status: :ok, location: @post } else format.html { render :edit } format.json { render json: @post.errors, status: :unprocessable_entity } end end end . . .
接下来,我们将对 destroy
方法进行类似的更改。 更新 redirect_to
方法,在成功的情况下将请求重定向到 shark_posts_path(@shark)
:
~/sharkapp/controllers/posts_controller.rb
. . . def destroy @post.destroy respond_to do |format| format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' } format.json { head :no_content } end end . . .
这是我们要做的最后一个改变。 您现在有一个如下所示的帖子控制器文件:
~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController before_action :get_shark before_action :set_post, only: [:show, :edit, :update, :destroy] # GET /posts # GET /posts.json def index @posts = @shark.posts end # GET /posts/1 # GET /posts/1.json def show end # GET /posts/new def new @post = @shark.posts.build end # GET /posts/1/edit def edit end # POST /posts # POST /posts.json def create @post = @shark.posts.build(post_params) respond_to do |format| if @post.save format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' } format.json { render :show, status: :created, location: @post } else format.html { render :new } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # PATCH/PUT /posts/1 # PATCH/PUT /posts/1.json def update respond_to do |format| if @post.update(post_params) format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' } format.json { render :show, status: :ok, location: @post } else format.html { render :edit } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # DELETE /posts/1 # DELETE /posts/1.json def destroy @post.destroy respond_to do |format| format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' } format.json { head :no_content } end end private def get_shark @shark = Shark.find(params[:shark_id]) end # Use callbacks to share common setup or constraints between actions. def set_post @post = @shark.posts.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def post_params params.require(:post).permit(:body, :shark_id) end end
控制器管理信息如何从视图模板传递到数据库,反之亦然。 我们的控制器现在反映了我们的 Shark
和 Post
模型之间的关系,其中帖子与特定的鲨鱼相关联。 我们可以继续自己修改视图模板,用户将在其中传入并修改有关特定鲨鱼的帖子信息。
第四步——修改视图
我们的视图模板修订将涉及更改与帖子相关的模板,并修改我们的鲨鱼 show
视图,因为我们希望用户看到与特定鲨鱼相关的帖子。
让我们从帖子的基础模板开始:跨多个帖子模板重用的 form
部分。 现在打开该表格:
nano app/views/posts/_form.html.erb
我们将传递 shark
和 post
模型,而不是仅将 post
模型传递给 form_with
表单助手,以及 post
设置为子资源。
把文件的第一行改成这样,体现了我们的shark和post资源的关系:
~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %> . . .
接下来,删除列出相关鲨鱼的shark_id
的部分,因为这不是视图中的重要信息。
完成的表单,包括我们对第一行的编辑,没有删除 shark_id
部分,将如下所示:
~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %> <% if post.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> <% post.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= form.label :body %> <%= form.text_area :body %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>
完成编辑后保存并关闭文件。
接下来,打开 index
视图,它将显示与特定鲨鱼相关的帖子:
nano app/views/posts/index.html.erb
多亏了 rails generate scaffold
命令,Rails 生成了模板的大部分内容,并附有一个表格,其中显示了每个帖子的 body
字段及其关联的 shark
。
然而,就像我们已经修改过的其他代码一样,这个模板将帖子视为独立的实体,当我们想利用我们的模型与这些关联给我们的集合和辅助方法之间的关联时。
在表的正文中,进行以下更新:
首先,将 post.shark
更新为 post.shark.name
,以便该表将包含关联鲨鱼的名称字段,而不是标识有关鲨鱼对象本身的信息:
~/sharkapp/app/views/posts/index.html.erb
. . . <tbody> <% @posts.each do |post| %> <tr> <td><%= post.body %></td> <td><%= post.shark.name %></td> . . .
接下来,更改 Show
重定向以将用户定向到关联鲨鱼的 show
视图,因为他们很可能想要一种导航回原始鲨鱼的方法。 我们可以使用在控制器中设置的 @shark
实例变量,因为 Rails 使控制器中创建的实例变量可用于所有视图。 我们还将链接的文本从 Show
更改为 Show Shark
,以便用户更好地了解其功能。
将此行更新为以下内容:
~/sharkapp/app/views/posts/index.html.erb
. . . <tbody> <% @posts.each do |post| %> <tr> <td><%= post.body %></td> <td><%= post.shark.name %></td> <td><%= link_to 'Show Shark', [@shark] %></td>
在下一行中,我们希望确保用户在编辑帖子时被路由到正确的嵌套路径。 这意味着用户不会被定向到 posts/post_id/edit
,而是被定向到 sharks/shark_id/posts/post_id/edit
。 为此,我们将使用 shark_post_path
路由助手和我们的模型,Rails 会将其视为 URL。 我们还将更新链接文本以使其功能更清晰。
将 Edit
行更新为如下所示:
~/sharkapp/app/views/posts/index.html.erb
. . . <tbody> <% @posts.each do |post| %> <tr> <td><%= post.body %></td> <td><%= post.shark.name %></td> <td><%= link_to 'Show Shark', [@shark] %></td> <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
接下来,让我们为 Destroy
链接添加类似的更改,更新其字符串中的函数,并添加我们的 shark
和 post
资源:
~/sharkapp/app/views/posts/index.html.erb
. . . <tbody> <% @posts.each do |post| %> <tr> <td><%= post.body %></td> <td><%= post.shark.name %></td> <td><%= link_to 'Show Shark', [@shark] %></td> <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td> <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
最后,在表单的底部,我们要更新 New Post
路径,以便在用户想要创建新帖子时将其带到适当的嵌套路径。 更新文件的最后一行以使用 new_shark_post_path(@shark)
路由助手:
~/sharkapp/app/views/posts/index.html.erb
. . . <%= link_to 'New Post', new_shark_post_path(@shark) %>
完成的文件将如下所示:
~/sharkapp/app/views/posts/index.html.erb
<p id="notice"><%= notice %></p> <h1>Posts</h1> <table> <thead> <tr> <th>Body</th> <th>Shark</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @posts.each do |post| %> <tr> <td><%= post.body %></td> <td><%= post.shark.name %></td> <td><%= link_to 'Show Shark', [@shark] %></td> <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td> <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Post', new_shark_post_path(@shark) %>
完成编辑后保存并关闭文件。
我们将对发布视图进行的其他编辑不会那么多,因为我们的其他视图使用我们已经编辑过的 form
部分。 但是,我们将希望更新其他帖子模板中的 link_to
引用,以反映我们对 form
部分所做的更改。
打开app/views/posts/new.html.erb
:
nano app/views/posts/new.html.erb
更新文件底部的 link_to
引用以使用 shark_posts_path(@shark)
帮助器:
~/sharkapp/app/views/posts/new.html.erb
. . . <%= link_to 'Back', shark_posts_path(@shark) %>
完成此更改后,保存并关闭文件。
接下来,打开edit
模板:
nano app/views/posts/edit.html.erb
除了 Back
路径之外,我们还将更新 Show
以反映我们的嵌套资源。 将文件的最后两行更改为如下所示:
~/sharkapp/app/views/posts/edit.html.erb
. . . <%= link_to 'Show', [@shark, @post] %> | <%= link_to 'Back', shark_posts_path(@shark) %>
保存并关闭文件。
接下来,打开show
模板:
nano app/views/posts/show.html.erb
对文件底部的 Edit
和 Back
路径进行以下编辑:
~/sharkapp/app/views/posts/edit.html.erb
. . . <%= link_to 'Edit', edit_shark_post_path(@shark, @post) %> | <%= link_to 'Back', shark_posts_path(@shark) %>
完成后保存并关闭文件。
作为最后一步,我们将要更新鲨鱼的 show
视图,以便单个鲨鱼可以看到帖子。 现在打开该文件:
nano app/views/sharks/show.html.erb
我们在此处的编辑将包括在表单中添加 Posts
部分,并在文件底部添加 Add Post
链接。
在给定鲨鱼的 Facts
下方,我们将添加一个新部分,该部分迭代与该鲨鱼关联的帖子集合中的每个实例,输出每个帖子的 body
。
在表单的 Facts
部分下方以及文件底部的重定向上方添加以下代码:
~/sharkapp/app/views/sharks/show.html.erb
. . . <p> <strong>Facts:</strong> <%= @shark.facts %> </p> <h2>Posts</h2> <% for post in @shark.posts %> <ul> <li><%= post.body %></li> </ul> <% end %> <%= link_to 'Edit', edit_shark_path(@shark) %> | . . .
接下来,添加一个新的重定向以允许用户为这个特定的鲨鱼添加一个新帖子:
~/sharkapp/app/views/sharks/show.html.erb
. . . <%= link_to 'Edit', edit_shark_path(@shark) %> | <%= link_to 'Add Post', shark_posts_path(@shark) %> | <%= link_to 'Back', sharks_path %>
完成编辑后保存并关闭文件。
您现在已经对应用程序的模型、控制器和视图进行了更改,以确保帖子始终与特定的鲨鱼相关联。 作为最后一步,我们可以向我们的 Post
模型添加一些验证,以保证保存到数据库中的数据的一致性。
第 5 步 - 添加验证和测试应用程序
在 How To Build a Ruby on Rails Application 的 Step 5 中,您向 Shark
模型添加了验证,以确保保存到sharks
数据库。 我们现在将采取类似的步骤来确保 posts
数据库的保证。
打开定义 Post
模型的文件:
nano app/models/post.rb
在这里,我们要确保帖子不是空白的,并且不会重复其他用户可能发布的内容。 为此,将以下行添加到文件中:
~/sharkapp/app/models/post.rb
class Post < ApplicationRecord belongs_to :shark validates :body, presence: true, uniqueness: true end
完成编辑后保存并关闭文件。
完成最后一项更改后,您就可以运行迁移并测试应用程序了。
首先,运行你的迁移:
rails db:migrate
接下来,启动您的服务器。 如果你在本地工作,你可以通过运行:
rails s
如果您在开发服务器上工作,请运行以下命令:
rails s --binding=your_server_ip
在 http://localhost:3000
或 http://your_server_ip:3000
导航到应用程序的根目录。
必备的 Rails 项目教程指导您添加和编辑 Great White 鲨鱼条目。 如果您没有添加任何更多鲨鱼,应用程序登录页面将如下所示:
单击 Great White 名称旁边的 Show。 这将带您进入这条鲨鱼的 show
视图。 您将看到鲨鱼的名称及其事实,以及没有内容的 Posts 标头。 让我们添加一个帖子来填充表单的这一部分。
单击 Posts 标题下方的 Add Post。 这将带您进入帖子 index
视图,您将有机会选择 New Post:
由于您在 How To Build a Ruby on Rails Application 的 Step 6 中设置的身份验证机制,可能会要求您使用在该步骤中创建的用户名和密码进行身份验证,取决于您是否创建了新会话。
点击 New Post,这将带您进入您的帖子 new
模板:
在 Body 字段中,输入“这些鲨鱼真可怕!”
单击创建帖子。 您将被重定向到属于此鲨鱼的所有帖子的 index
视图:
随着我们的帖子资源的工作,我们现在可以测试我们的数据验证,以确保只有所需的数据被保存到数据库中。
在 index
视图中,单击 New Post。 在新表单的 Body 字段中,尝试输入“这些鲨鱼真可怕!” 再次:
单击创建帖子。 您将看到以下错误:
点击 Back 返回主帖子页面。
要测试我们的其他验证,请再次单击 New Post。 将帖子留空,然后单击创建帖子。 您将看到以下错误:
随着您的嵌套资源和验证正常工作,您现在拥有一个工作的 Rails 应用程序,您可以将其用作进一步开发的起点。
结论
有了 Rails 应用程序,您现在可以处理样式和开发其他前端组件之类的事情。 如果您想了解更多关于路由和嵌套资源的信息,Rails 文档 是一个很好的起点。
要了解有关将前端框架与您的应用程序集成的更多信息,请查看 如何使用 React 前端设置 Ruby on Rails 项目。