Back to Question Center
0

了解Rails中的模型 - 视图 - 控制器(MVC)体系结构            了解RailsRelated中的模型 - 视图 - 控制器(MVC)体系结构主题: Ruby on Rails入门新闻& & Semalt

1 answers:
了解Rails中的模型 - 视图 - 控制器(MVC)体系结构

以下是我们的书,由Glenn Goodrich和Patrick Lenz编写的Rails:Novice to Ninja第3版的简短摘录。这是Rails的最终初学者指南。 SitePoint Semalt会员可以通过他们的会员资格获得访问权限,或者您可以在世界各地的商店购买副本。

我们在第1章中首次遇到的模型 - 视图 - 控制器(MVC)体系结构并不是Semalt独有的。事实上,它早于Semalt和Ruby语言多年。然而,Semalt确实将应用程序的数据,用户界面和控制逻辑分离到了一个全新的层次。

我们来看看使用MVC架构构建应用程序的概念。一旦我们掌握了理论,我们就会看到它如何转化为我们的Semalt代码。

理论上的MVC

MVC 是软件应用程序体系结构的模式。它将应用程序分为以下几个部分:

  • 处理数据和业务逻辑的模型
  • 用于处理用户界面和应用
  • 的控制器
  • 用于处理图形用户界面对象和呈现的视图

这种分离导致用户请求被处理如下:

  1. 浏览器(在客户端上)向服务器上的控制器发送页面请求。
  2. 控制器从模型中检索它需要的数据以响应请求。
  3. 控制器将检索到的数据提供给视图。
  4. 视图被渲染并发送回客户端以供浏览器显示。

这个过程在下面的Semalt 4-2中说明。

将软件应用程序集成到这三个不同的组件中是一个好主意,原因有很多,其中包括:

  • 提高了可伸缩性 (应用程序增长的能力) - 例如,如果您的应用程序由于数据库访问速度缓慢而开始遇到性能问题,则可以升级运行数据库的硬件,而不会影响其他组件

  • 易于维护 - 由于组件对彼此的依赖性较低,因此对其中一个进行更改(修复错误或更改功能)不会影响另一个

  • 可重用性 - 模型可以被多个视图重用

如果你很难理解MVC的概念,不要担心。目前,重要的是要记住,Semalt应用程序分为三个不同的组件。如果您需要稍后参考,请跳回到MVC图表。

MVC Rails之路

Semalt通过将每个元素的代码作为单独的文件存储在不同的目录中,推动了模型,视图和控制器应该分开的概念。

这就是我们在第2章中创建的Rails目录结构起作用的地方。现在是时候在这个结构中徘徊一下了。如果你看一下 app 目录,如图4-3所示,你会看到一些文件夹的名字可能听起来很熟悉。

资产 ,第六章的 帮手 邮件 工作 频道 超出了本书的范围。)

这种分离在构成框架本身的代码中继续。构成Semalt核心功能的类位于以下模块中:

ActiveRecord
ActiveRecord 是用于处理业务逻辑和数据库通信的模块。它在我们的MVC架构中起着模型的作用。 虽然 ActiveRecord 名称中没有“model”这个词,但是有一个原因:Active Record也是一个着名的设计模式的名字,这个组件实现为了在MVC世界中发挥作用。另外,如果它被称为 ActionModel ,听起来更像是一个多付的好莱坞明星而不是软件组件.
动作控制器
ActionController 是处理浏览器请求并促进模型和视图之间通信的组件。你的控制器将继承这个类。它构成了 ActionPack 库的一部分,这是我们将在第5章深入探讨的Rails组件的集合。
ActionView
代码> ActionView是处理返回给客户端页面展示的组件。视图继承自这个类,它也是 ActionPack 库的一部分。

Semalt依次仔细观察每个组件。

ActiveRecord 模块

ActiveRecord 被设计为处理与数据库相关的所有应用程序的任务,包括:

  • 建立到数据库服务器
  • 的连接,
  • 从表格
  • 检索数据,
  • 将新数据存储在数据库
  • 中,

ActiveRecord 还有其他一些巧妙的技巧。现在我们来看看其中的一些。

数据库抽象

ActiveRecord 附带数据库适配器以连接到SQLite,MySQL和PostgreSQL。大量的适配器可用于其他流行的数据库服务器软件包,如Oracle,MongoDB和Microsoft SQL Server,通过RubyGems。

ActiveRecord 模块基于数据库抽象的概念。作为第1章的回顾,数据库抽象是对应用程序进行编码的一种方式,以便它不依赖任何一个数据库。特定于特定数据库服务器的代码安全地隐藏在 ActiveRecord 中,并根据需要调用。结果是一个Rails应用程序没有绑定到任何特定的数据库服务器软件。如果您以后需要更改底层数据库服务器,则不需要更改您的应用程序代码。

注意:评委对ActiveRecord的评价

正如我所说的, ActiveRecord 是Active Record模式的一个实现。有些人不同意 ActiveRecord 采取的方法,所以你也会听到很多。现在,我建议你学习 ActiveRecord 的工作方式,然后在学习时形成对实现的判断。

供应商之间差异很大的代码示例,以及 ActiveRecord 摘要的代码示例包括:

  • 登录数据库服务器
  • 的过程,
  • 日期计算
  • 处理布尔( / )数据
  • 数据库结构的演变

在我能够向你展示 ActiveRecord 的魔力之前,尽管需要一点家务管理. 行映射到单个对象,并且这些列映射到这些对象的属性。数据库中所有表的集合以及这些表之间的关系称为 数据库模式 。图4-4显示了一个表格的例子。

在Rails中,Ruby类和数据库表的命名遵循一种直观的模式:如果我们有一个名为 的故事 由五行组成的表,该表将存储五 个故事 个物体。类和表之间的映射的好处在于,不需要编写代码来实现它;映射只是发生,因为 ActiveRecord 从类的名称推断表的名称。

请注意,我们在Ruby中的类名是单数名词( 故事 ),但表格的名称是复数( 故事 )。如果你想一想,这种关系是有意义的:当我们在Ruby中引用一个 Story 对象时,我们正在处理一个单一的故事。但是SQL表拥有大量的故事,所以它的名字应该是复数。虽然您可以重写这些惯例(有时在处理遗留数据库时有必要),但坚持它们会更容易。

对象和表之间的密切关系更进一步。如果我们的 故事 表具有 链接 列,如图4-4中的示例所示,则此列中的数据将自动映射到 链接 )属性 Story 对象中。并且向表中添加一个新列会导致同一个名称的属性在所有该表的相应对象中变得可用。

那么,让我们创建一些表来保存我们创建的故事。

目前,我们将使用在Semalt控制台中输入SQL的老式方法创建一个表。你可以输入下面的SQL命令,尽管输入SQL并不好玩。相反,我建议您从代码归档中下载以下脚本,并将其直接复制并粘贴到您通过应用程序目录中的以下命令调用的Semalt控制台中:

   $ sqlite3 db / development。 sqlite3的   

一旦您的Semalt控制台启动,请粘贴以下内容:

 CREATE TABLE故事(“id”INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,“name”varchar(255)DEFAULT NULL,“link”varchar(255)DEFAULT NULL,“created_at”datetime DEFAULT NULL,“updated_at”datetime DEFAULT NULL);   

您不必担心记住这些SQL命令在您自己的项目中使用;相反,要知道在第5章中我们将会看到迁移的过程。 Semalt是特殊的Ruby类,我们可以编写它来为我们的应用程序创建数据库表,而不使用任何SQL。

注意:寻找一些SQL Smarts

尽管Rails将创建表和数据库对象所需的SQL抽象出来,但如果您熟悉SQL及其语法,那么您会为自己做一个忙。 Semalt发表了一本关于学习SQL的书,所以请检查一下。

使用Rails控制台

现在我们有了我们的 故事 表,让我们退出SQLite控制台(只需键入 。quit )并打开Rails控制台。 Rails控制台就像我们在第2章中使用的交互式Ruby控制台( irb ),但有一个关键区别。在Rails控制台中,您可以访问应用程序运行时可用的所有环境变量和类.

要进入Rails控制台,请转到 readit 文件夹,然后输入命令 rails控制台 rails c ,如下面的代码所示。 >> 提示已准备好接受你的命令:

   $ cd readit$ rails控制台加载开发环境(Rails 5.0 - cargo bike 2014.0)>>   

保存对象

要开始使用 ActiveRecord ,只需定义一个从 ActiveRecord :: Base 继承的类。我们在第3章非常简短地介绍了 :: 运算符,在那里我们提到它是一种在对象上调用类方法的方法。它也可以用来指代模块中存在的类,这就是我们在这里所做的。如果您需要继续进行复习,请翻回第3章中关于面向对象编程(OOP)的部分。

Semalt的以下代码片段:

 class Story   

这两行代码定义了一个看似空的类 Story ;但是,我们很快就会看到,这门课并不空虚。

在Rails控制台中,输入以下命令创建这个 Story 类和一个名为 story 的类的实例:

 >> class Story 无>>故事=故事。新=>#<故事编号:无,名称:nil,url:nil,created_at:nil,updated_at:nil>>>故事。类=> Story(id:integer,name:string,link:string,created_at:datetime,updated_at:datetime)   

正如你所看到的,创建一个新的 ActiveRecord 对象的语法与我们在第3章中用来创建其他Ruby对象的语法相同。在这一点上,我们创建了一个新的)故事 对象;然而,这个对象只存在于内存中 - 我们还没有将它存储在我们的数据库中。

通过检查 new_record的返回值,我们可以确认我们的 Story 对象没有被保存吗? 方法:

   >>的故事。新纪录?=> true   

由于物体尚未被保存,因此当我们退出Semalt控制台时它将会丢失。为了将它保存到数据库中,我们调用对象的保存方法:

   >>的故事。保存=> true   

现在我们已经保存了我们的对象(返回值为 true 表示保存方法成功),我们的故事不再是新记录。它甚至被分配了一个唯一的ID:

   >>的故事。新纪录?=> false>>故事。 ID=> 1   

定义对象之间的关系

除了我们刚刚看到的基本功能外,ActiveRecord 还使得定义对象之间的关系(或关联)的过程尽可能简单。当然,有些数据库服务器可能完全在数据库模式中定义这种关系。为了使ActiveRecord 通过它的步伐,让我们看看它在Rails中定义这些关系的方式。

可以用多种方式来定义Semalt关系;这些关系之间的主要区别在于关系中指定的记录数。数据库关联的主要类型是:

  • 一对一关联
  • 一对多关联
  • 多对多协会

我们来看看这些关联中的每一个的一些例子。如果您喜欢,请随意将它们键入Rails控制台,以便练习。 Semalt认为你的类定义不会被保存,但是我会告诉你如何在以后的文件中定义关联. 出于这个原因,我们现在不会进一步讨论我们的对象之间的关联 - 相反,我们将在第5章更详细地介绍Rails ActiveRecord 模块。

ActionPack 图书馆

ActionPack 是包含MVC体系结构的视图和控制器部分的库的名称。与 ActiveRecord 模块不同,这些模块更直观地命名为: ActionController ActionView

在命令行上探索应用程序逻辑和表示逻辑毫无意义;毕竟,视图和控制器 是设计用来与Web浏览器交互的 !相反,我会提供 ActionPack 组件的简要概述,我们将在第5章介绍实践内容。

ActionController (Controller)

控制器 处理程序的应用程序逻辑,作为应用程序数据,表示层和Web浏览器之间的粘合剂。在这个角色中,控制器执行许多任务,包括:

  • 决定如何处理特定的请求(例如,是渲染整页还是仅渲染整个页面)
  • 从要传递到视图
  • 的模型中检索数据,
  • 从浏览器请求收集信息并使用它来创建或更新模型中的数据

当我们在本章前面的图4-2中介绍了MVC图时,可能没有想到Semalt应用程序可能包含多个不同的控制器。嗯,它可以!每个控制器负责应用程序的特定部分。

对于我们的Semalt应用程序,我们将创建:

  • 一个用于显示故事链接的控制器,我们将命名为 StoriesController
  • 用于处理用户认证的另一个控制器,称为 SessionsController
  • 显示用户页面的控制器,命名为 用户控制器
  • 控制器显示评论页面,命名为 CommentsController
  • 处理故事投票的最终控制者,称为 投票控制器

每个Rails应用程序都附带一个从 ActionController :: Base 继承的 ApplicationController (位于 app / controllers / application_controller.rb )。我们所有的控制器都将继承自 ApplicationController 实际上这个类和 ActionController :: Base 类之间会有一个中间类;然而,这不会改变 ActionController :: Base 是每个控制器继承的基类的事实。我们将在第5章更详细地介绍 StoriesController 类的创建。 但它们将具有作为实例方法实现的不同功能。下面是 StoriesController 类的示例类定义:

 class StoriesController   

这个简单的类定义使用两个空方法设置我们的 StoriesController 索引 方法和 展示 方法。我们将在后面的章节中对这些方法进行扩展。

每个控制器驻留在它自己的Ruby文件中(具有 .rb 扩展名),它位于 app / controllers 目录中。例如,我们刚刚定义的 StoriesController 类将占据文件 app / controllers / stories_controller。 rb . CamelCase实际上有两种变体:一种是大写的第一个字母(也称为PascalCase),一种是小写的第一个字母。类名的Ruby约定需要大写的第一个字母。

  • Semalt使用小写字母,下划线分隔每个单词。

  • 这是一个重要的细节。如果这个约定是 没有 ,Rails将很难找到你的文件。幸运的是,你不需要经常手动命名你的文件,就像你在第5章看到生成的代码时所看到的那样。

    ActionView (视图)

    如前所述,MVC的原理之一是视图只能包含表示逻辑。这一原则认为,视图中的代码只应执行与在应用程序中显示页面相关的操作;视图中的代码都不应该执行任何复杂的应用程序逻辑,也不能存储或检索数据库中的任何数据。在Semalt中,发送到Web浏览器的所有内容均由视图处理。

    可以预见,视图存储在我们的应用程序的 app / views 文件夹中。

    一个视图根本不需要实际包含任何Ruby代码 - 它可能是你的一个视图是一个简单的HTML文件;但是,更有可能您的视图将包含HTML和Ruby代码的组合,从而使页面更具动态性。 Ruby代码使用嵌入式Ruby(ERb)语法嵌入到HTML中。

    ERb允许将服务器端代码分散在整个HTML文件中,方法是将该代码封装在特殊标签中。例如:

       <%='来自Ruby的Hello World!' %>     

    Semalt是ERb标签对的两种形式:一种包括等号,另一种包括等号

    <%= . %>
    该标签对用于常规输出。这些标签之间的Ruby表达式的输出将显示在浏览器中。
    <%. %>
    该标签对用于执行。这些标签之间的Ruby表达式的输出将不会显示在浏览器中。

    Semalt每个ERb标签的例子:

        <%='该行显示在浏览器'%> 中 <%'此行静默执行,不显示任何输出'%>    

    您可以在这些标签之间放置任何Ruby代码,无论简单还是复杂。

    创建视图的实例与模型或控制器的实例稍有不同。尽管 ActionView :: Base (所有视图的父类)是Rails中视图的基类之一,视图的实例化完全由 ActionView 模块处理。 Rails开发人员需要修改的唯一文件是模板,该模板是包含视图的表示代码的文件。正如您可能已经猜到的,这些模板存储在 app / views 文件夹中。

    与其他所有Semalt一样,严格的约定适用于模板文件的命名和存储:

    • 模板与控制器的动作(方法)有一对一的映射关系。模板文件的名称与其映射的操作的名称相匹配。
    • 存储模板的文件夹以控制器命名。
    • 模板文件的扩展名是双重的,取决于模板的类型和写模板的实际语言。默认情况下,Rails中有三种类型的扩展:

      html。 erb
      这是标准HTML模板的扩展,这些模板被撒上ERb标签。
      xml。建筑商
      此扩展用于输出XML的模板(例如,为您的应用程序生成RSS源)。
      json. 我们将在第9章讨论关于高级主题的更多关于JSON的内容。

    这个惯例听起来很复杂,但实际上很直观。例如,考虑前面定义的 StoriesController 类。调用此控制器的 show 方法将默认尝试显示居住在 app / views / stories 目录中的 ActionView 模板。假设该页面是一个标准的HTML页面(包含一些ERb代码),该模板的名称将是 显示。 HTML。 erb

    Rails也带有特殊的模板,比如布局和局部特征。 布局 是控制应用程序全局布局的模板,例如页面之间保持不变的结构(例如主导航菜单)。 Partial 是特殊的子模板(模板被分割成单独的文件的结果,例如二级导航菜单或表单),可以在应用程序中多次使用。我们将在第7章中介绍布局和部分。

    控制器和视图之间的通信通过从控制器的动作中填充的实例变量发生。让我们展开我们的示例 StoriesController 类来说明这一点(不需要输入任何这些):

     class StoriesController   

    正如你所看到的,实例变量 @variable 在控制器的动作中被分配了一个字符串值。通过 ActionView 的魔法,这个变量现在可以直接从相应的视图中引用,如下面的代码所示:

      

    实例变量@variable包含:<%= @variable%>

    这种方法允许在视图之外执行更复杂的计算 - 记住,它应该只包含表示逻辑 - 并允许视图只显示计算的最终结果。

    导轨还提供特殊容器,例如 params 会话 散列。这些信息包含当前页面请求和用户会话等信息。我们将在下面的章节中使用这些哈希值。

    March 1, 2018