`

rails数据传递技巧

阅读更多

本文分析了 Rails 3 的 MVC 架构,探讨总结了 Rails 3 的控制器与视图、控制器与模型、视图与布局以及多个视图之间的数据传输方法和技巧。

Rails 3 简介

Ruby on Rails 是一个 Ruby 实现、采用 MVC 模式的开源 Web 应用开发框架,能够提供 Web 应用的全套解决方案。它的“习惯约定优于配置”的设计哲理,使得 Web 开发人员能够从繁琐的配置中解放出来,专注于核心的应用逻辑。“习惯约定优于配置”是 Rails 根据最佳经验习惯,提供可直接使用的功能及规范,而不再需要开发人员通过复杂的配置文件进行具体繁琐的设置。Ruby on Rails 快速高质的开发特性及其数量众多的免费插件,吸引了包括 Twitter、Groupon 和 Hulu 等大批互联网新贵。

回页首

快速创建 Rails 3 应用程序

为了逐步演示 Rails 3 的功能特性,此处采用增量模式开发一个简单的博客模型。 在安装完 Rails3 之后,运行命令:Rails new demoBlog 。

demoBlog 应用程序所需的各类文件就自动生成。进入生成的文件夹 demoblog,运行自动安装 demoBlog 所需 gem 的命令:bundle install 。

然后在 $rorails/demoblog/config/database.yml 中简单地配置数据库文件,运行创建数据库的命令:rake db:create 。

至此,简单的 demoBlog 创建完毕,运行服务器启动命令:rails server 。

打开 http://localhost:3000 就可以看到 Rails 3 的典型欢迎页面,如图 1 所示。

图 1. Rails 3 的典型欢迎页面

图 1. Rails 3 的典型欢迎页面

Rails 脚手架可以快速地为新资源建立起模型、视图和控制器,而不必处理其中的细节。直接运行以下命令,为 demoBlog 建立一个 article 脚手架,用于管理博客里的文章。运行脚手架建立命令:rails generate scaffold Article title:string keywords:string content:text

这将生成 article 控制器、 article 的视图文件和含有 title、 keyword 及 content 三个属性的 article 模型。运行数据库迁移命令,生成相关数据表:rake db:migrate 。 此时,一个简单但结构完整的文章管理系统就开发完成。 通过 URL:http://localhost:3000/articles/就可以直接访问其文章管理页面。

回页首

Rails 3 MVC 架构解析

Rails 3 采用 MVC(Model 模型、View 视图、Controller 控制器)层级架构实现核心功能模块。这不仅使业务逻辑独立于用户界面,代码清晰易于维护,还能够提高代码重复利用率,达成 Rails“不重复自己”的原则。Rails 中 MVC 的功能分别如下:

Model(模型):代表应用系统的数据信息以及操作这些数据的规则;

View(视图):代表应用系统的用户接口,通常是包含嵌入式 Ruby 代码的 HTML 文件,用于向浏览器提供数据的工作;

Controller(控制器):主要负责处理 Web 请求,检索模型数据并按要求将数据传递给视图。控制器是模型和视图的联系桥梁。

以上文创建的 demoBlog 应用程序为例,用户为访问文章列表,输入页面的 URL:http://localhost:3000/article 打开页面,对应的 Web 请求处理流程如图 2 所示,大致步骤如下:

浏览器发出 Web 请求

路由模块将请求信息发送给相应的控制器,由控制器决定如何处理请求;

控制器根据请求处理逻辑,调用相应的模型来完成业务逻辑;

根据实际需求,完成数据的检索或存储;

控制器组织处理信息,调用视图解析从模型返回的数据;

完成页面渲染,返还数据给浏览器。

图 2. Rails 3 MVC 事件处理流程图

图 2. Rails 3 MVC 事件处理流程图

通过 Rails 3 典型的内部处理流程,可以看到 Rails 3 的 MVC 结构清晰,分工明确。那么这些功能紧密联系的模块,是如何完成数据传递,又有哪些技巧呢?许多初学者都为此困惑不已,笔者将在下文的进行详细地分析介绍。

回页首

控制器与视图间的数据传递方法技巧

打开视图文件夹,找到用于实现文章列表的源文件 $rorails/demoBlog/app/views/articles/index.html.erb,可以看到清单 1 所示代码。这段代码对变量 @articles 迭代,显示所有文章列表的属性值。

清单 1. 视图 index.html.erb 代码片段

 

<% @articles.each do |article| %> 
  <tr> 
    <td><%= article.title %></td> 
    <td><%= article.keywords %></td> 
    <td><%= article.content %></td> 
    <td><%= link_to 'Show', article %></td> 
    <td><%= link_to 'Edit', edit_article_path(article) %></td> 
    <td><%= link_to 'Destroy', article, :confirm => 
    'Are you sure?', :method => :delete %></td> 
  </tr> 
 <% end %>

 

让初学者困惑不已的是,此处的变量 @articles 来自何处呢?为了解决这个问题,打开 article 控制器的源文件 $rorails/demoblog/app/controllers/articles_controller.rb,找到与 index.html.erb 对应的 index 方法,可以看到变量 @articles,如清单 2 所示。视图中的 @articles 变量正是由控制器生成赋值,然后传递给视图的,并且这个传递过程对开发人员而言是透明的。换句话说,视图可以直接使用对应控制器中对应方法的变量。

清单 2. 控制器中获取数据的代码片段

  

def index 
    @articles = Article.all 
    respond_to do |format| 
      format.html # index.html.erb 
      format.xml  { render :xml => @articles } 
    end 
  end

 

用户打开 http://localhost:3000/articles/new 发表新文章,控制器将通过 @article = Article.new,基于 Article 模型创建一个值为空的数据,然后传输给 new.html.erb 视图,显示效果如图 3 所示。用户在这个空的页面上填写数据,点击“Create Article”创建文章。文章创建成功,返回文章创建成功的提示信息和新创建文章的内容,如图 4 所示。这里看似一个简单的过程,实际上包含了将数据从表单传递到控制器,进而传递到模型完成存储的过程。

图 3. 新创建文章

图 3. 新创建文章

图 4. 文章创建成功

图 4. 文章创建成功

渲染视图的代码位于 _form.html.erb(被 new.html.erb 调用)。用户点击提交后,Rails 将根据路由规则跳转到控制器的 create 方法。过程的确简单,但是用户填写到表单的数据是如何传递给控制器的呢?

控制器的 create 方法如下清单 3 所示。为了创建新的 article 对象,create 方法将从 params 中读取数据 :article 参数。这里的 params 是哈希表,它是 Rails 里最重要的传递参数之一,包含浏览器请求传递的数据。正是这个 params 将数据从客户端表单传递到控制器。以此处为例,新建的文章表单数据(包括 Title,Keywords,Content)将被封装到 article 对象,通过 params 传递到控制器。

清单 3. 控制器的 create 方法

  

def create 
    @article = Article.new(params[:article]) 
    respond_to do |format| 
      if @article.save 
        format.html { 
      redirect_to(@article, :notice => 'Article was successfully created.') }
        format.xml  { 
      render :xml => @article, :status => :created, :location => @article } 
      else 
        format.html { 
      render :action => "new" } 
        format.xml  { 
      render :xml => @article.errors, :status => :unprocessable_entity } 
      end 
    end 
  end

 

Rails 应用程序可以用两种方法的把数据传给 params,进而由控制器的某个方法获取。一种是将用户输入到 HTML 表单的数据封装到 HTTP 请求,通过 POST 方法将数据传给控制器的 params。上文采用的就是这种方法,将 new.html.erb 视图的表单数据通过 POST 方法提交。另外一种方法就是通过把数据作为 URL 的一部分,位于 URL 中 ? 之后,通常称为 URL 查询字符串参数。Rails 并没有对这两种方法传递的数据做出区分,控制器都能够以前文述及的方法从 params 中获取数据。以 URL:http://127.0.0.1:3000/articles?keywords%5b%5d=Hello&keywords%5b%5d=Test& keywords%5b%5d=Article 为例,params[:keywords] 将存储 [“Hello”, “Test”, “Article”]。

回页首

控制器与模型间的数据传递方法技巧

正如图 2 所示,控制器是连接视图与模型的关键组件,它不仅接收来自视图的表单数据,还可以将模型里的数据传递给视图。比起控制器与视图之间的数据传递,控制器与模型的数据相互传递更容易理解。

参考代码清单 3,控制器通过 Article.new(params[:article]) 的方法创建一个 Article 实例,然后由 @article.save 将数据存储到数据库表中。这个过程如此的简单,看起来控制器是直接与数据库交换的,并没有涉及任何模型。打开模型源文件 $rorails/rorails/demoblog/app/models/ article.rb,如清单 4 所示。模型代码竟然如此简洁,连实体关系模型中常见的属性定义都没有。实际上,Rails 中模型的属性是靠命名规则与数据库字段实现关联的。模型数据的属性定义是在对应的 migrate 文件中。控制器直接使用 create,save 和 update 等继承自父类 ActiveRecord::Base 的方法,实现数据创建、存储和更新,不需要额外的编写代码。

清单 4. Article 模型的代码

 class Article < ActiveRecord::Base 

 end

在 Rails 中,控制器获取模型数据过程也是相当的方便快捷。打开控制器源文件,update 方法如清单 5 所示。Rails 按照路由规则把请求 URL 中的 ID 值,通过 params 传递给控制器。Article.find 方法根据 :id 查找现有的数据,然后使用 update_attributes 方法更新记录。Rails 控制器正是通过 ActiveRecord 的 find 方法从模型中读取数据。

清单 5. 控制器 update 方法

  

def update 
    @article = Article.find(params[:id]) 
    respond_to do |format| 
      if @article.update_attributes(params[:article]) 
        format.html { 
        redirect_to(
        @article, :notice => 'Article was successfully updated.') } 
        format.xml  { head :ok } 
      else 
        format.html { render :action => "edit" } 
        format.xml  { 
        render :xml => 
        @article.errors, :status => :unprocessable_entity } 
      end 
    end 
  end

 

Rails 3 封装了控制器、模型乃至数据库之间的数据映射关系,极大地简化了数据操作过程,数据存取异常方便,充分体现了 Rails 的“习惯约定优于配置”设计哲理。

回页首

视图内的数据共享

视图与布局间的数据共享

在 Rails 3 之后,通过脚手架生成的视图布局位于 layouts/application.html.erb,能够被所有的控制器共享。布局和视图可以共享控制器中的数据。也就是说,布局可以用与视图完全一样的方法获取控制器中的数据。

然而在某些特殊的情况下,布局需要读取一些视图的信息。以 demoBlog 为例,为了能够在文章列表显示页面的标题上显示文章的总篇数,可以在 index.html.erb 末尾添加代码如清单 6 所示。

清单 6. 视图 index 读取文章总篇数

 

<% content_for :ArticleNumber do %> 
  <%= @articles.length %> 
 <% end %>

 

在布局源文件的头部,添加 yield 方法,如清单 7 所示。这样 <% content_for :ArticleNumber do %> 标签里的信息,就可以在 <%= yield :ArticleNumber %> 指定的位置显示。文章的篇数信息在页面头部的最终显示效果如图 5 所示。

清单 7. 通过布局源文件显示

 

<head> 
  <title>Demoblog has  <%= yield :ArticleNumber %> articles. </title> 
  <%= stylesheet_link_tag :all %> 
  <%= javascript_include_tag :defaults %> 
  <%= csrf_meta_tag %> 
 </head>

 

图 5. 文章总篇数的最终显示效果

图 5. 文章总篇数的最终显示效果

上述的例子比较特殊,但却很好地阐述了布局读取视图数据的方法。需要注意的是,布局是不能向视图传递信息的,因为视图的执行是在布局引入或者说发生作用之前。

视图之间的数据

视图之间经常需要传递数据,Rails 为此进行了精心设计。它不仅提供特有的 flash 快捷机制,也支持传统的 Session 和 Cookie 功能。需要说明的是,此节讲述的数据传递过程,本质上还是从控制器到视图的。因为对用户而言,数据是从某个视图获取,然后通过另外一个视图显示出来。因为中间的控制器对开发者而言近乎透明,所以姑且将此类型定义为视图之间的数据传递。

Rails 的 flash 机制尤其适用于前后关联的视图页面之间传递数据。从本质上看, flash 是 Rails 内建的一个哈希表,用于从一个控制器向另一个控制器的视图发送用户所需的消息。当控制器调用 redirect_to 时,重定向会清空除 flash 之外的所有变量。

以文章修改更新为例,需要在下一个页面(此处是显示文章的页面,对应 show 的 action)告诉用户完成的结果。对应的 update 方法如前文代码清单 5 所示,很显然,更新成功的提示消息 'Article was successfully updated.' 赋值给了 :notice, 而后者正是 flash 哈希表的最常用的一个键。除了 :notice 之外,:error, :alert, warning 键也是相当常见的。提示文章更新成功的消息显示效果如图 6 所示。

图 6. 提示文章更新成功

图 6. 提示文章更新成功

通常,添加到 flash 的数据能够在紧接着的下个请求里读取。但是某些情况下,您想在当前请求中直接使用。比如文章创建失败,直接渲染页面的情况下,就不会导致新的请求。如果此时需要显示 flash 中的信息,可以用 flash.now 方法实现。

flash 的使用必须注意几点:首先,为了保证性能, flash 中存储的数据不能过长。其次,flash 的内容只能跨越一次重定向,如果希望数据能够在重定向后依然有效,需要在重定向之前使用 flash.keep。

为了演示 Rails 是如何使用 Cookie 和 Session 的,此处将为文章添加读者评论功能。整个创建过程非常简单,以下一条命令就能够创建评论所需的数据库表并实现嵌套映射:

rails generate model Comment user:string comment:text article:references

运行迁移数据库命令:rake db:migrate,添加评论显示代码,就可以获取如图 7 所示的读者评论功能。

图 7. 读者发表文章评论

图 7. 读者发表文章评论

Cookie 通常是由服务器端发送给浏览器的,用于存储少量用户信息的文本。基于 Rails 的应用多数情况下不需要直接存取 Cookie,因为 Rails 内置的会话机制或者第三方的插件都能够支持用户信息管理。存储在 Cookie 中的数据可以跨请求甚至跨会话, 所以用户也可以直接使用 Cookie 存取数据。

Rails 提供非常简便的 Cookie 访问方法。为了提示用户使用相同的用户名发表评论,此处采用 Cookie 来保存用户最近一次发表评论时使用的用户名。如清单 8 所示,通过 cookies[:name] 来读取或者保存用户名。

清单 8. 创建评论的控制器代码片段

 

class CommentsController < ApplicationController 
  def create 
    @last_name = cookies[:name] 
    @name = params[:comment][:user] 
    unless @name == @last_name 
      cookies[:last_name] = @last_name 
      cookies[:name] = @name 
    else 
      cookies[:last_name] = nil 
    end 
  end 
 end

 

在文章控制器中,如清单 9 所示,可以将 Cookies 保存的数据读取出来,使用非常方便。评论页面的显示效果如图 8 所示。

清单 9. 通过 cookie 操作数据

 

def show 
    @article = Article.find(params[:id]) 
    @last_name = cookies[:last_name] 
    unless @last_name == nil 
    @name = cookies[:name] 
 end

 

图 8. 文章评论显示效果

图 8. 文章评论显示效果

Rails 应用程序经常使用 session 来实现多个请求之间的数据传递,session 对象在控制器和视图中都可以使用。现在我们新增加一个 session 对象,用于保存用户使用过的姓名列表。在 CommentsController 中,session 对象的操作如清单 10 所示。

清单 10. 通过 session 操作数据的代码片段

   

 @names = session[:name] 
    if @names 
      @names = [] 
    end 
    if @name 
      @names << @name 
    end 
    session[:names] = @names

 

在视图中,添加显示用户名列表的代码,如清单 11 所示。页面最终显示效果如图 9 所示。

清单 11. 视图读取用户名列表的代码

 

<% if @names %> 
 <p>The names you have used:</p> 
 <ul> 
  <% @names.each do |name| %> 
    <li><%=h name %></li> 
  <% end %> 
 </ul> 
 <% end %>

 

分享到:
评论

相关推荐

    Ruby on Rails中MVC结构的数据传递解析

    文章中提到的“控制器与视图间的数据传递方法技巧”主要涉及Rails中如何在控制器和视图之间共享数据。在Rails中,控制器通常会将数据赋值给一个实例变量(如@articles),这个实例变量在视图模板中可以直接访问。...

    剖析Rails3MVC中的数据传递

    如果读者已经开发过基于Rails的应用,但对其MVC间的数据传递还有诸多困惑,那么恭喜您,本文正是要总结梳理Rails数据传递的方法和技巧。RubyonRails3(以下统称为Rails3)是当前的主要发布版本,本文所述及的内容和...

    rails cookbook

    《Rails Cookbook》是一本...通过这本书,读者不仅可以学习到Rails的使用方法,还能了解到良好的开发实践和技巧,提升自己的Rails开发技能。同时,博客链接提供的额外资源可作为补充学习材料,加深对书中内容的理解。

    Ruby on Rails入门经典代码

    通过学习和实践压缩包中的"Ruby on Rails入门经典代码",新手不仅可以了解Rails的基本概念,还能掌握实际项目中的应用技巧,逐步成长为一名熟练的Rails开发者。记得不断探索、实践和学习新的Rails知识,以适应不断...

    Rails 4 in Action, Second Edition.pdf

    - **Controllers**:控制器是处理用户请求的主要场所,它负责从模型获取数据并传递给视图展示。 - **Views**:视图层主要负责呈现数据,通常使用ERB(Embedded Ruby)模板语言编写。 #### 三、Rails 4中的高级主题 ...

    Ruby on Rails入门权威经典

    此外,书中还会探讨如何利用Rails的强大力量,如局部变量、实例变量和实例方法来传递数据给视图。 控制器(Controller)是连接模型和视图的桥梁,负责处理HTTP请求和响应。书中会讲解如何定义动作、处理参数、...

    关于rails学习中分页的示例

    在Rails开发中,分页是...理解并熟练掌握分页技巧,能够帮助你在开发大型数据集的应用时提高性能和用户体验。同时,这也是Rails开发者必备的一项技能。通过阅读给出的博文链接,你将获得更深入的实践指导和示例代码。

    Flexible Rails: Flex3 on Rails2

    2. **路由匹配**:Web服务器将请求传递给Rails中的路由代码,根据`config/routes.rb`中定义的路由规则触发相应的控制器方法。 3. **控制器逻辑**:控制器方法被调用后,会与各种ActiveRecord模型进行交互,这些模型...

    rails-beginner-s-guide

    《Rails初学者指南》是一本专为初学...《Rails初学者指南》为初学者提供了一个全面、系统的学习Rails框架的路径,不仅涵盖了基础知识点,还深入探讨了Rails中高级特性以及实践技巧,是一本非常有价值的Rails入门教材。

    ruby on rails入门

    - **控制器**:控制器是 MVC 模式中的核心组件之一,用于处理用户的请求,并将数据传递给视图展示。Rails 默认提供了 CRUD 操作的控制器方法,如 `index`、`show`、`new`、`create` 等。 - **视图**:视图负责展示...

    flex on rails文档

    3. Web 服务器将请求传递给 **Rails** 中的路由代码,该代码根据配置文件 `config/routes.rb` 中定义的路由触发相应的控制器方法。 4. 调用控制器方法。该方法通过与各种 ActiveRecord 模型(这些模型被持久化到选择...

    ruby on rails入门基础

    - Controller(控制器)作为模型和视图之间的桥梁,处理用户请求并传递数据。 5. **数据库集成**: - Rails默认使用SQLite,但也可以配置使用MySQL、PostgreSQL等其他数据库。在本例中,`libmySQL.dll`可能是一个...

    simply rails

    - **控制器**:解释控制器如何处理用户请求,并将数据传递给视图进行渲染。 #### 6. **助手、表单和布局** - **助手方法**:描述Rails提供的各种助手方法,用于简化视图中的代码编写。 - **表单生成**:教授如何...

    Rails入门

    在提供的"Rails培训.ppt"文件中,可能会详细讲解以上内容,包括示例代码、步骤演示和实用技巧。通过这个教程,初学者可以快速掌握Rails的基本用法,为进一步深入学习和实际项目开发打下坚实的基础。同时,实践是检验...

    Ruby on Rails敏捷开发最佳实践源代码

    通过学习和实践这些源代码,开发者不仅可以深入了解Ruby on Rails框架的工作原理,还能掌握如何利用Rails进行敏捷开发,提升自己的编程技巧和项目管理能力。无论是初学者还是经验丰富的开发者,都能从中受益匪浅。

    rails-react-components-源码.rar

    在"rails-react-components-源码"中,我们可以看到如何定义React组件,以及如何通过props传递数据和方法。组件化开发提高了代码的可读性和可维护性,降低了复杂性。 2. **Webpack与Rails的集成** Rails默认使用...

    Agile Web Development with Rails 第三版(中文版)

    5. **辅助方法和局部变量**:Rails提供了丰富的辅助方法来简化视图层的编码,同时也介绍了如何在控制器中定义和使用局部变量,以便在视图中传递数据。 6. **Rails测试**:书中强调了测试的重要性,并展示了如何编写...

Global site tag (gtag.js) - Google Analytics