Rails 初上手指南

$ gem install rails
 
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ gem install rails
</pre></div>
<p></p>
<p><span class="caps">TIP</span>: 如果你在 Window 下面工作,你可以使用 <a href="http://railsinstaller.org">Rails Installer</a> 快速安装 Ruby and Rails。</p>
<p>确认所有的(依赖)安装正确,你应该运行如下命令:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rails --version
</pre>
</div>
<p>如果终端提示类似这样的文字 “Rails 3.2.2” 那么你已经准备好继续了。</p>
<h4 id="5-2">5.2 Creating the Blog Application</h4>
<p>开始,打开一个 terminal,导航至一个你有权限创建文件的文件夹,并输入:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rails new blog #--skip-bundle   
# Don't run bundle install这样在国内就不会由于连不上gem即便上能够上也会很慢半天没反映 可以尝试使用 淘宝gem镜像
</pre>
</div>
<p>这里将在名称为 blog 的目录中创建一个名叫 Blog 的 Rails 应用程序。</p>
<p><span class="caps">TIP</span>: 你可以通过运行 rails new -h,查看 Rails 应用程序创建器的所有命令(开关)。</p>
<p>当你创建了这个 blog 程序,跳转到它所在的文件夹中(直接对这个程序编辑)。
</p><div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ cd blog
 
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ cd blog
</pre><p></p>
</div>
<p></p>
<p>命令 <tt>rails new blog</tt> 将会在你的工作目录中创建一个名为 <tt>blog</tt> 的文件夹。目录 <tt>blog</tt> 包含一些自动生成的文件(夹),它构成了 Rails  应用程序的结构。在这个体验中的大多数的工作都是在 app/ 这个文件夹中完成的,这里对 Rails 默认创建的每一个文件和文件夹的功能做出了一个概述:</p>
<table>
     <tbody><tr>
         <th>File/Folder</th>
         <th>Purpose</th>
     </tr>
     <tr>
         <td>app/</td>
         <td>包含 controllers, models, views 和 你应用程序的 assets(资源),再接下来的手册中你主要的注意力应该放在这里。</td>
     </tr>
     <tr>
         <td>config/</td>
         <td>配置你的应用程序的运行的规则,(url)路由,数据库和其他,更多的信息查看 <a href="http://guides.rubyonrails.org/configuring.html">Configuring Rails Applications</a></td>
     </tr>
     <tr>
         <td>config.ru</td>
         <td>基于 Rack 服务器使用这个应用程序的 Rack 配置用于开始应用程序(Rack configuration for Rack based servers used to start the application)</td>
     </tr>
     <tr>
         <td>db/</td>
         <td>显示你当前的数据库结构(database schema),同样也显示数据迁移。</td>
     </tr>
     <tr>
         <td>doc/</td>
         <td>应用程序的(深入)全面的文档。</td>
     </tr>
     <tr>
         <td>Gemfile<br>Gemfile.lock</td>
         <td>这个文件让你可以(添加)你的 Rails 所需要的特殊的 Gem 依赖关系。这个文件被 Bundler gem 使用,更多的信息查看 <a href="http://gembundler.com">the Bundler website</a> </td>
     </tr>
     <tr>
         <td>lib/</td>
         <td>应用程序用到的扩展库(本手册没有涉及)</td>
     </tr>
     <tr>
         <td>log/</td>
         <td>应用程序的日志文件</td>
     </tr>
     <tr>
         <td>public/</td>
         <td>这是外部可见的唯一文件夹。包含静态文件和编译资源。</td>
     </tr>
     <tr>
         <td>Rakefile</td>
         <td>这个文件定位和载入能够在命令行中运行的任务。这个任务定义贯穿整个 Rails 的组件。除了修改 Rakefile,你更应该添加你自己的任务的文件到你的应用程序的 lib/tasks 目录。</td>
     </tr>
     <tr>
         <td><span class="caps">README</span>.rdoc</td>
         <td>这是一个简单的说明手册。你需要编辑这个文件告诉其他人你的应用程序可以做什么,怎么安装等等。</td>
     </tr>
     <tr>
         <td>script/</td>
         <td>包含运行你的 app 的 rails 脚本,或者其他用来配置或运行你的应用程序的 scripts。</td>
     </tr>
     <tr>
         <td>test/</td>
         <td>单元测试, fixtures,或者其他 test 工具。他们在 <a href="http://guides.rubyonrails.org/testing.html">Testing Rails Applications</a> 里面有完整的讲述。</td>
     </tr>
     <tr>
         <td>tmp/</td>
         <td>临时文件</td>
     </tr>
     <tr>
         <td>vendor/</td>
         <td>放置第三方代码的地方。在一个典型的 Rails 应用程序中,这里包含 Ruby Gems,Rails 源代码(如果你把 Rails 安装到你的项目中)还包含一些预先安装好的额外的插件</td>
     </tr>
</tbody></table>
<h3 id="6">6 配置一个数据库</h3>
<p>几乎每个 Rails 应用程序都会和一个数据库交互。使用的数据库在一个配置文件 <tt>config/database.yml</tt> 中被指定。如果你打开一个在新的 Rails 应用程序的中的配置文件,你将会看到默认的数据库被配置使用 SQLite3。这个文件包含 Rails 默认能够运行的三个不同环境的部分:</p>
<ul>
     <li>development 环境被使用在你的开发/本地计算机作为你与应用程序的手动交互。</li>
     <li>test 环境被使用来运行自动测试。</li>
     <li>production 环境在你部署你的应用程序给所有人使用的时候使用。</li>
</ul>
<p><span class="caps">TIP</span>: 你不必手动的更新数据库配置。如果你查看应用程序创建器的选项,你将会发现其中一个选项叫—— database。这个选项允许你从最常使用的关系数据库列表中选择一个适配器。你甚至可以反复运行创建器命令: <tt>cd .. && rails new blog —database=mysql</tt>。当你确认重写 <tt>config/database.yml</tt> 文件,你的应用程序将会被配置为 MySQL 以替代 SQLite。下面是一些常用数据库连接的详细的例子。</p>
<h4 id="6-1">6.1 配置一个 SQLite3 数据库</h4>
<p>Rails 内置支持 <a href="http://www.sqlite.org/">SQLite</a> ,这是一个轻量级的非服务器(serverless)数据库应用程序。虽然 SQLite 可能无法应对繁忙的产品环境,但它在开发和测试环境可以很好的工作。Rails 在创建一个新的项目的时候默认使用一个 SQLite 数据库,但是你总是可以在以后改变它。</p>
<p>这里是一个开发环境(数据库)连接信息默认配置文件(<tt>config/database.yml</tt>)的节选:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">development:
   adapter: sqlite3
   database: db/development.sqlite3
   pool: 5
   timeout: 5000
</pre>
</div>
<p><span class="caps">TIP</span>: 在这个教程中我们使用一个 SQLite3 数据库来存储数据,因为它无需配置就可以工作。Rails 同样也支持“开箱即用”的 MySQL 和 PostgreSQL,以及很多数据库系统的插件。如果你正在产品环境中使用一个数据库,大多数情况下 Rails 都有一个与之相应的插件。</p>
<h4 id="6-2">6.2 配置一个 MySQL 数据库</h4>
<p>如果你选择使用一个 MySQL 替代(项目初始化)附带的 SQLite3 数据库,你的 <tt>config/database.yml</tt> 将会看起来有些不同。这里是 development 部分:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">development:
   adapter: mysql2
   encoding: utf8
   database: blog_development
   pool: 5
   username: root
   password:
   socket: /tmp/mysql.sock
</pre>
</div>
<p>如果你的开发电脑的 MySQL 安装的时候包含了一个名叫 ‘root’ 的用户以及一个空密码,这个配置文件应该会为你工作。否则,在 development 部分更改为合适的用户名和密码。</p>
<h4 id="6-3">6.3 配置一个 PostgreSQL 数据库</h4>
<p>如果你选择使用 PostgreSQL,你的 <tt>config/database.yml</tt> 将会定制来使用 PostgreSQL 数据库:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">development:
   adapter: postgresql
   encoding: unicode
   database: blog_development
   pool: 5
   username: blog
   password:
</pre>
</div>
<h4 id="6-4">6.4 配置一个用于 JRuby 平台的 SQLite3 数据库</h4>
<p>如果你选择使用 SQLite3 并且使用 JRuby,你的 <tt>config/database.yml</tt> 将会看起来有点不同。这里是 development 部分:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">development:
   adapter: jdbcmysql
   database: blog_development
   username: root
   password:
</pre>
</div>
<h4 id="6-5">6.5 配置一个用于 JRuby 平台的 PostgreSQL 数据库</h4>
<p>最后如果你选择使用 PostgreSQL 并且正在使用 JRuby,你的 <tt>config/database.yml</tt>将会看起来有点不同。这里是 development 部分:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">development:
   adapter: jdbcpostgresql
   encoding: unicode
   database: blog_development
   username: blog
   password:
</pre>
</div>
<h3 id="7">7 Hello, Rails!</h3>
<p>开始学习一门新语言的一种比较传统的方式是快速的在屏幕上输出一些文字。要得到这样的结果你需要使你的 Rails 程序能够正常运行。</p>
<h4 id="7-1">7.1 启动web服务</h4>
<p>你实际上已经有了一个 Rails 功能的应用程序了。看一看它,你需要在你的开发机器上启动一个 web 服务,你可以这样来启动。</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rails server
</pre>
</div>
<p><span class="caps">TIP</span>: 编译 CoffeeScript 到 JavaScript需要一个 JavaScript 运行库,缺少运行库将会给出一个 <tt>execjs</tt> error。通常 Mac OS X 和 Windows 自带了一个 JavaScript 运行库。Rails 添加了 <tt>therubyracer</tt>  gem 到 Gemfile 的注释行中,如果你需要,可以取消对它的注释。对于 JRuby 用户,推荐使用 <tt>therubyrhino</tt> 运行环境。它已经默认添加到 Gemfile 中,如果应用程序在 JRuby 中创建。你可以查看所有的支持的运行库 <a href="https://github.com/sstephenson/execjs#readme。">ExecJS</a></p>
<p>这里默认将开启一个 WEBrick 服务器的的实例(Rails 也可能使用一些其他的 web 服务器)。查看你的应用程序的行为,打开一个浏览器并且导航到 <a href="http://localhost:3000">http://localhost:3000</a> 你将会看到一个 Rails 默认的信息页面。</p>
<p><img src="images/rails_welcome.png" title="Welcome Aboard screenshot" alt="Welcome Aboard screenshot" data-pinit="registered"></p>
<p><span class="caps">TIP</span>: 要终止 web 服务,在命令运行的终端中按下 Ctrl+C 。在开发环境模式中,Rails 一般不需要你停止服务;你所做的更改将自动的编译进需要的文件中并且重启服务。</p>
<p>这个欢迎界面是新的 Rails 应用程序的 <a href="http://www.hudong.com/wiki/%E5%86%92%E7%83%9F%E6%B5%8B%E8%AF%95">冒烟测试</a> ,用以确保你的软件正确配置完毕,足以运行一个页面。你可以点击 ‘About your application’s environment’ 查看你的应用程序运行环境的摘要信息。</p>
<h4 id="7-2">7.2 Rails 说 Hello"</h4>
<p>要使 Rails 说出(显示)“你好”,你至少需要创建一个 controller 和 view。幸运的是,你可以通过一行命令完成这些。在终端中输入:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rails generate controller home index
</pre>
</div>
<p><span class="caps">TIP</span>: 如果你在输入这个命令的时候出现"没有这个命令"的错误,你需要明确的使用 ruby 来执行 Rails 命令。</p>
<p>Rails 将会为你创建一些文件,包含 <tt>app/views/home/index.html.erb</tt> 。这是一个模板,用来显示在 home controller 中的 index action (method) 的结果。在文本编辑器中打开这个文件并输入:</p>
<p><code class="html">
<h1>Hello, Rails!</h1>
</code></p>
<h4 id="7-3">7.3 设置应用程序主页</h4>
<p>现在我们已经创建了 controller 和 view,我们还需要告诉 Rails 我们想在什么时候显示出来。在本例中,我们想让它在我们访问站点 url 根目录 <a href="http://localhost:3000">http://localhost:3000</a> 的时候替代 “Welcome Aboard” 显示。</p>
<p>首先移除应用程序中的默认页面。</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rm public/index.html
</pre>
</div>
<p>我们必须这样做,因为 Rails 将会优先传送 public 文件夹中的静态文件,而不是我们从 controllers 中生成的动态(显示)内容。</p>
<p>现在你还必须告诉 Rails 你实际上的主页在哪里。在文本编辑器中打开 <tt>config/routes.rb</tt> 。这是你应用程序的路由文件,它采用 <span class="caps">DSL</span> 语言囊括了告诉 Rails 怎样连接请求信息到 controllers 和 actions的所有条目。这个文件包含许多简单的路由命令,其中一条就是用于告诉我们怎样连接你站点根目录到一个指定的 controller and action。找到以 root :to 开头的那一行,注释掉它改成如下内容:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">Blog::Application.routes.draw do
 
   #...
   # You can have the root of your site routed with "root"
   # just remember to delete public/index.html.
   root :to => "home#index"
</pre>
</div>
<p><tt>root :to => "home#index"</tt> 告诉 Rails 映射请求到应用程序的 root action 到 home 控制器的 index action。</p>
<p>现在你在浏览器中访问 <a href="http://localhost:3000">http://localhost:3000</a> ,你将会看到“Hello, Rails!”.</p>
<p>NOTE. 更多的信息请参见 <a href="routing.html">Rails Routing from the Outside In</a>.</p>
<h3 id="8">8 使用 Scaffolding 快速创建并运行</h3>
<p>Rails ‘scaffolding’ 是一个建立应用程序的一些重要组件的快速的方法。如果你想使用单行操作为新资源创建 models,views 和 controllers,Scaffolding 是一个不错的工具。</p>
<h3 id="9">9 创建一个资源</h3>
<p>在本示例中的 blog 应用程序,你可以使用 scaffolded 产生 post 资源:它表现为一个简单的 blog posting。要完成这些,在终端输入如下命令:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">rails generate scaffold Post name:string title:string content:text
</pre>
</div>
<p>创建器将会在应用程序中的一些文件夹中生成一些文件,并且还会编辑 <tt>config/routes.rb</tt>。下面是这些产生的文件的大概说明:</p>
<table>
     <tbody><tr>
         <th>File/Folder</th>
         <th>Purpose</th>
     </tr>
     <tr>
         <td>db/migrate/20100207214725_create_posts.rb </td>
         <td>将创建的posts表单迁移到你的数据库(会在你的命名前面加上时间戳)</td>
     </tr>
     <tr>
         <td>app/models/post.rb </td>
         <td>Post模型</td>
     </tr>
     <tr>
         <td>test/unit/post_test.rb </td>
         <td>posts 模型的单元测试工具</td>
     </tr>
     <tr>
         <td>test/fixtures/posts.yml </td>
         <td>测试使用的 posts 样例</td>
     </tr>
     <tr>
         <td>config/routes.rb  </td>
         <td>用以编辑 posts 的路由信息</td>
     </tr>
     <tr>
         <td>app/controllers/posts_controller.rb</td>
         <td>Posts 控制器</td>
     </tr>
     <tr>
         <td>app/views/posts/index.html.erb</td>
         <td>显示所有 posts 的视图</td>
     </tr>
     <tr>
         <td>app/views/posts/edit.html.erb </td>
         <td>编辑 post 的视图</td>
     </tr>
     <tr>
         <td>app/views/posts/show.html.erb </td>
         <td>显示一条 post 的视图</td>
     </tr>
     <tr>
         <td>app/views/posts/new.html.erb </td>
         <td>创建 post 的视图</td>
     </tr>
     <tr>
         <td>app/views/posts/_form.html.erb </td>
         <td>一个局部用于控制编辑和创建新视图的整体视效的表单</td>
     </tr>
     <tr>
         <td>test/functional/posts_controller_test.rb</td>
         <td>posts 控制器的功能测试工具</td>
     </tr>
     <tr>
         <td>app/helpers/posts_helper.rb </td>
         <td>用于 post 视图的帮助函数(Helper functions)</td>
     </tr>
     <tr>
         <td>test/unit/helpers/posts_helper_test.rb  </td>
         <td>the posts helper 的单元测试工具</td>
     </tr>
     <tr>
         <td>app/assets/javascripts/posts.js.coffee </td>
         <td>用于 the posts controller 的 CoffeeScript</td>
     </tr>
     <tr>
         <td>app/assets/stylesheets/posts.css.scss</td>
         <td>用于 the posts controller 的 <span class="caps">CSS</span></td>
     </tr>
     <tr>
         <td>app/assets/stylesheets/scaffolds.css.scss </td>
         <td>使创建的视图更优美的 <span class="caps">CSS</span> 层叠样式</td>
     </tr>
</tbody></table>
<p>NOTE. 即便 scaffolding 使你创建和运行非常快捷,但是产生的代码不可能完全适合你的应用程序。你大多数都需要定制产生的代码。很多有经验的Rails开发人员完全不使用 scaffolding,宁愿从头编写全部的代码。无论如何,Rails 使得为生成的models,controllers,views或者其他代码定制模板非常简单。你可以在 <a href="http://guides.rubyonrails.org/generators.html">Creating and Customizing Rails Generators & Templates</a> 看到更多信息。</p>
<h4 id="9-1">9.1 执行数据迁移</h4>
<p><tt>rails generate scaffold</tt> 命令的一个产物就是数据迁移。Migrations是一个ruby类,用于简化数据库表单的创建和修改。Rails使用 rake 命令来执行迁移,它还可以撤销已经应用的修改。 迁移文件名包含了一个时间戳,以确保迁移工作能够按照正确的顺序完成。</p>
<p>如果你查看 <tt>db/migrate/20100207214725_create_posts.rb</tt> 这个文件(记住,你看到的名字可能会略微不同),你将会看到如下代码:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">class CreatePosts < ActiveRecord::Migration
   def change
     create_table :posts do |t|
     t.string :name
     t.string :title
     t.text :content
 
     t.timestamps
     end
   end
end
</pre>
</div>
<p>整个 migration 创建了一个名叫 change 的方法,该方法在你运行这个 migration 的时候被调用。这个方法中定义的行为也是可逆的,那就是说,如果你需要恢复到上一次数据,Rails 知道怎样逆向改变这个 migration。默认情况下,当你运行这个 migration,他将会创建一个包含两个字符串列和一个 text 列的表单。关于 Rails migration 的更多信息请阅读 <a href="http://guides.rubyonrails.org/migrations.html">Rails Database Migrations</a> 手册。</p>
<p>这个时候,你可以使用 rake 命令运行 migration 了:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">rake db:migrate
</pre>
</div>
<p>Rails 将会执行这个 migration 命令并且通知你它创建了 Post 表单。</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">==  CreatePosts: migrating =============================================
-- create_table(:posts)
    -> 0.0019s
==  CreatePosts: migrated (0.0020s) ====================================
</pre>
</div>
<p><span class="caps">TIP</span>: 由于你默认工作在开发环境中,这个命令将会应用于开发环境会话的数据库(在你的 <tt>config/database.yml</tt> 中有定义)。如果你想在其他环境中执行 migration,比如以产品(环境)为实例,你必须通过命令行中执行:<tt>rake db:migrate RAILS_ENV=production</tt> 来明确的调用。</p>
<h4 id="9-2">9.2 添加一个 Link</h4>
<p>你已经创建好的 post 挂到主页上,你可以通过添加一个 link 到主页。打开 <tt>app/views/home/index.html.erb</tt> 并且按照下面所示更改:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><h1>Hello, Rails!</h1>
<%= link_to "My Blog", posts_path %>
</pre>
</div>
<p>这个链接方法是 Rails 在 view helpers 的内建方法之一 。它创建一个基于文字的超级链接并显示到哪里,在这个实例中(跳转)到 posts。</p>
<h4 id="9-3">9.3 Working with Posts in the Browser</h4>
<p>现在你已经准备好在 posts 中工作了。导航至 <a href="http://localhost:3000,并且点击">http://localhost:3000</a> “My Blog” 链接。</p>
<p><img src="images/posts_index.png" title="Posts Index screenshot" alt="Posts Index screenshot" data-pinit="registered"></p>
<p>这就是 Rails 渲染你的 posts 视图后的结果。在你点击 “New Post” 链接并创建一个新的 post 之前,数据库里面是没有任何 post 的。随后你可以编辑,查看详细内容,或者删除他们。post 的所有的 logic 和 <span class="caps">HTML</span> 都是通过 <tt>rails generate scaffold</tt> 命令生成的。</p>
<p><span class="caps">TIP</span>: 在开发模式中(你的默认工作模式),Rails 会在每个浏览器请求的时候重新载入你的应用程序,因此你不需要停止或者重启 web 服务。</p>
<p>恭喜,你已经驯服了 rails!现在是时候去看看它怎样工作的了。</p>
<h4 id="9-4">9.4 The Model</h4>
<p>如你所见, model 文件 <tt>app/models/post.rb</tt> 非常简单:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">class Post < ActiveRecord::Base
     attr_accessible :content, :name, :title
end
</pre>
</div>
<p>这个文件内容并不多——但是注意 <tt>Post</tt> 类继承于 <tt>ActiveRecord::Base</tt>。Active Record 免费为你的 models 提供了强大的功能,包括基本数据库的 CRUD(创建,读取,更新,删除)操作,数据验证,以及复杂的的查询与其它数据表单多关联的字段的支持能力。另外一个重要的部分是 <tt>attr_accessible</tt> 。它指定了允许批量更新的属性的白名单。</p>
<h4 id="9-5">9.5 添加一些验证</h4>
<p>Rails 包含一些帮助你验证发送到models的数据的方法。打开 <tt>app/models/post.rb</tt> 并编辑:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">class Post < ActiveRecord::Base
   attr_accessible :content, :name, :title  
   validates :name,  :presence => true
   validates :title, :presence => true,
                     :length => { :minimum => 5 }
end
</pre>
</div>
<p>这些更改会确保所有的 post 都有一个 name 和 titile 并且 title 长度至少五个字符。Rails 可以验证很多种字段,比如字段能否为空和独特性,字段的格式,以及字段的关联。验证详细描述在 <a href="active_record_validations_callbacks.html#validations-overview">Active Record Validations and Callbacks</a></p>
<h4 id="9-6">9.6 使用控制台</h4>
<p>要想在action里面查看你的验证你可以使用 console。console 是一个可以让你在你的应用程序的上下文中执行 Ruby 代码的命令行工具:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">$ rails console
</pre>
</div>
<p><span class="caps">TIP</span>: 默认的 console 将会改变你的数据库。你可以通过运行 <tt>rails console
—sandbox</tt>,这样你可以(在退出控制台后)回滚你的任何操作。</p>
<p>在载入控制台后,你可以使用它来对你应用程序的models进行工作:</p>
<div class="code_container">
<pre class="brush: plain; gutter: false; toolbar: false">>> p = Post.new(:content => "A new post")
=> #<Post id: nil, name: nil, title: nil,
      content: "A new post", created_at: nil,
      updated_at: nil>
>> p.save
=> false
>> p.errors.full_messages
=> ["Name can't be blank", "Title can't be blank", "Title is too short (minimum is 5 characters)"]
</pre>
</div>
<p>这段代码演示了创建一个 <tt>Post</tt> 实例,并企图保存到数据库,结果得到一个 <tt>false</tt> 的返回值(说明保存失败的原因),同时检查了 post 的错误信息。</p>
<p>当你操作完成,输入 <tt>exit</tt> 并回车退出 console。</p>
<p><span class="caps">TIP</span>: 不像开发环境的 web 服务器,console 不会自动导入你每行输入的新的代码。如果你改变了你的 models 并且 console 是打开的,输入 <tt>reload!</tt> 那么 console 会立即导入他们。</p>
<h4 id="9-7">9.7 Listing All Posts</h4>
<p>让我们稍微深入 Rails 代码,去看看程序是怎样展示 post 列表给我们的。打开文件 <tt>app/controllers/posts_controller.rb</tt> 并且查看 <tt>index</tt> action:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def index
   @posts = Post.all
 
   respond_to do |format|
     format.html  # index.html.erb
     format.json  { render :json => @posts }
   end
end
</pre>
</div>
<p><tt>Post.all</tt> 调用 Post model 并返回当前在数据库中的所有 post 为一个 <tt>Post</tt> 记录的数组。并且我们将这个数组存储在一个叫做@posts的实例变量中。</p>
<p><span class="caps">TIP</span>: 有关 Active Record 更多的信息,可以查看 <a href="active_record_querying.html">Active
Record Query Interface</a> 相关记录。</p>
<p>这个 <tt>respond_to</tt> 块处理了这个动作的 <span class="caps">HTML</span> 和 <span class="caps">JSON</span> 请求。如果你浏览 <a href="http://localhost:3000/posts.json,你将会看到一个包含着所有">http://localhost:3000/posts.json</a> post 的 <span class="caps">JSON</span> 数组。这个 <span class="caps">HTML</span> 格式在 <tt>app/views/posts/</tt> 的 view 中查找相对应的动作名称。Rails 使来自 action 的所有的(可用的)实例变量对应到view。<tt>app/views/posts/index.html.erb</tt> 代码如下。</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><h1>Listing posts</h1>
 
<table>
   <tr>
     <th>Name</th>
     <th>Title</th>
     <th>Content</th>
     <th></th>
     <th></th>
     <th></th>
   </tr>
 
<% @posts.each do |post| %>
   <tr>
     <td><%= post.name %></td>
     <td><%= post.title %></td>
     <td><%= post.content %></td>
     <td><%= link_to 'Show', post %></td>
     <td><%= link_to 'Edit', edit_post_path(post) %></td>
     <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?',
                                      :method => :delete %></td>
   </tr>
<% end %>
</table>
 
<br />
 
<%= link_to 'New post', new_post_path %>
</pre>
</div>
<p>这个 view 迭代 <tt>@posts</tt> 数组所有的内容并显示相关的内容和链接。关于视图备注一些信息:</p>
<ul>
     <li><tt>link_to</tt> 创建一个超链接到一个地方</li>
     <li><tt>edit_post_path</tt> 和 <tt>new_post_path</tt> 是 Rails 提供的 RESTful 路由向导。你将会在不同 controller 看到一系列的不同的 actions helpers。</li>
</ul>
<p><span class="caps">NOTE</span>: 在以前的版本的 Rails 中,你必须使用 <tt><%=h post.name %></tt> 以避免一些HTML可能会在插入到页面之前转义。在 Rails 3.0 以及更高版本,这已作为默认。要得到一个非转义的 HTML,你现在使用 <tt><%= raw post.name %></tt>。</p>
<p><span class="caps">TIP</span>: 了解更过关于渲染处理流程,阅读 <a href="layouts_and_rendering.html">Layouts and Rendering in
Rails</a>.</p>
<h4 id="9-8">9.8 定制布局</h4>
<p>view 仅仅告诉 <span class="caps">HTML</span> 在你的 web 浏览器里面要显示什么(内容)。Rails 也有关于 <tt>layouts</tt> 的概念(定义),那就是布局是对 view 的包装。当 Rails 渲染一个 view 到浏览器,它通常是这样做: 把 view 的 <span class="caps">HTML</span> 放进布局的 <span class="caps">HTML</span> 中。在以前的版本中,<tt>rails generate scaffold</tt> 命令将会自动创建 controller 对应指定的布局,就像 <tt>app/views/layouts/posts.html.erb</tt> 对应于 posts controller。 然而在 rails3.0中有所不同了。一个应用程序指定的布局适用于所有的 controllers,可以在 <tt>app/views/layouts/application.html.erb</tt> 中找到(这就好像是django的base.html)。打开这个 layout 在你的编辑器中并且修改 <tt>body</tt> 标签:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><!DOCTYPE html>
<html>
   <head>
     <title>Blog</title>
     <%= stylesheet_link_tag "application" %>
     <%= javascript_include_tag "application" %>
     <%= csrf_meta_tags %>
   </head>
   <body style="background-color: #EEEEEE;">
     <%= yield %>
   </body>
</html>
</pre>
</div>
<p>现在你刷新 <tt>/posts</tt> 页面,你将会看到一个灰色的页面背景。并且相同的灰色背景将会使用在 posts 的所有视图中。</p>
<h4 id="9-9">9.9 建立新文章</h4>
<p>创建一个 new post 包含两个 actions。首先是 <tt>new</tt> action,它会实例化一个空的 <tt>Post</tt> 对象:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def new
   @post = Post.new
 
   respond_to do |format|
     format.html  # new.html.erb
     format.json  { render :json => @post }
   end
end
</pre>
</div>
<p>这个 <tt>new.html.erb</tt> 视图显示这个空的 post 给用户:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><h1>New post</h1>
 
<%= render 'form' %>
 
<%= link_to 'Back', posts_path %>
</pre>
</div>
<p><tt><%= render 'form' %></tt> 是我们第一个介绍的 Rails 的 partials。一个 partial 是一个 <span class="caps">HTML</span> 代码片段和 Ruby 代码的组合,可以在多目标对象中重用。(类似于django的include ‘other.html’)。
在本例中, form 用于创建 new post,它相当于一个用于编辑一个 post 的表单,这个表单有一个 name text fields 和 title text fields 以及一个 content 的 text area 还有一个用于添加一个新的 post 或者更新已经存在的 post 的按钮。</p>
<p>如果你看一下 <tt>views/posts/_form.html.erb</tt> 这个文件,你将会发现下面的内容:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><%= form_for(@post) do |f| %>
   <% if @post.errors.any? %>
   <div id="errorExplanation">
     <h2><%= pluralize(@post.errors.count, "error") %> prohibited
         this post from being saved:</h2>
     <ul>
     <% @post.errors.full_messages.each do |msg| %>
       <li><%= msg %></li>
     <% end %>
     </ul>
   </div>
   <% end %>
 
   <div class="field">
     <%= f.label :name %><br />
     <%= f.text_field :name %>
   </div>
   <div class="field">
     <%= f.label :title %><br />
     <%= f.text_field :title %>
   </div>
   <div class="field">
     <%= f.label :content %><br />
     <%= f.text_area :content %>
   </div>
   <div class="actions">
     <%= f.submit %>
   </div>
<% end %>
</pre>
</div>
<p>这个 partial 接收在 view 文件中定义的所有的实例变量。因此在本例中,controller 申请新的 Post 对象给@post,@post 在 view 和 partial 都是可用的。</p>
<p>有关 partials 的更多信息,参考 <a href="layouts_and_rendering.html#using-partials">Layouts and Rendering in
Rails</a> 指导。</p>
<p><tt>form_for</tt> 代码块用于创建一个HTML表单。在这个代码块中你可以在访问方法的基础上在表单上创建各种控制。比如,<tt>f.text_field :name</tt> 告诉 Rails 在表单中创建一个 text input 并且对应于显示实例的 <tt>name</tt> 属性。form 使用的方法基于 model 的相对应的字段属性(类型如 text_field 或 text_area)(例如本例中的 <tt>name</tt>, <tt>title</tt>, and <tt>content</tt>)。Rails 偏好于使用(偏向于使用)<tt>form_for</tt> 列出你要输入的 <span class="caps">HTML</span> 行因为这样代码更加简洁,并且这样使得 form 和 particular model 实例关系更加明显。</p>
<p><tt>form_for</tt> 代码块同样也足够你定制你的 <em>New Post</em> 和 <em>Edit Post</em> action,并且将会设置 form <tt>action</tt> 标签以及在 <span class="caps">HTML</span> 输出中显示的提交按钮的名称。</p>
<p><span class="caps">TIP</span>: 如果你需要创建一个显示任意的域的 <span class="caps">HTML</span> 表单,而不绑定到 model 字段中,你应该使用 <tt>form_tag</tt> 方法,它提供了建立不必绑定到 model 实例的 forms 的捷径。</p>
<p>当用户点击这张表单上面的 <tt>Create Post</tt> 按钮,浏览器将会发回信息到controller的 <tt>create</tt> action(Rails知道调用 <tt>create</tt> 方法,因为form是以HTTP POST请求发送,这是我随后提到的一种协议之一):</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def create
   @post = Post.new(params[:post])
 
   respond_to do |format|
     if @post.save
       format.html  { redirect_to(@post,
                     :notice => 'Post was successfully created.') }
       format.json  { render :json => @post,
                     :status => :created, :location => @post }
     else
       format.html  { render :action => "new" }
       format.json  { render :json => @post.errors,
                     :status => :unprocessable_entity }
     end
   end
end
</pre>
</div>
<p><tt>create</tt> action 实例化一个新的 Post 对象,这个对象给 form 提供数据支持,Rails 会生成有效的 <tt>params</tt> hash。当成功的保存了新 post,<tt>create</tt> 返回用户请求的适当的格式(在本例中是 HTML)。然后重定向用户页面到结果显示的 post show action页面并且给出提示 Post 成功的创建了。</p>
<p>如果 post 没有保存成功,是因为(数据)验证错误,然后 controller 控制用户页面回到 <tt>new</tt> action(包含验证错误新息)给用户,以便用户更改错误并重新提交。</p>
“Post was successfully created.” 这条消息被存储在 Rails 的 flash 的 hash 表中,(通常之叫它 <em>the flash</em> )因此消息可以转载到另一个 action,在请求状态中提供有用的信息给用户。在这个新建例子(数据验证失败)中,用户实际上从来不看任何在页面创建进程中的渲染页面,因为一旦 Rails 保存了这个记录,它立刻重定向页面到 new Post。Flash装载消息到接下来的 action,因此当用户被重定向到了 show action,他们立刻收到了一条消息 “Post was successfully created”。
<h4 id="9-10">9.10 显示一条 Post</h4>
<p>当你在posts 的主页面点击一个 post 的 <tt>show</tt> 这个超链接,他将会产生一个 url: <tt>http://localhost:3000/posts/1</tt>。Rails解释这是一个resource的<tt>show</tt> action 调用。这里是 <tt>show</tt> action:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def show
   @post = Post.find(params[:id])
 
   respond_to do |format|
     format.html  # show.html.erb
     format.json  { render :json => @post }
   end
end
</pre>
</div>
<p>这里的 <tt>show</tt> action使用 <tt>Post.find</tt> 通过对应记录的id来查找单个记录。当找到记录,Rails使用 <tt>app/views/posts/show.html.erb</tt> 来显示它:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><p id="notice"><%= notice %></p>
 
<p>
   <b>Name:</b>
   <%= @post.name %>
</p>
 
<p>
   <b>Title:</b>
   <%= @post.title %>
</p>
 
<p>
   <b>Content:</b>
   <%= @post.content %>
</p>
 
 
<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
</pre>
</div>
<h4 id="9-11">9.11 编辑Posts</h4>
<p>类似创建一个新的 post,编辑一个 post 分为两部分。首先是到 <tt>edit_post_path(@post)</tt> 请求一个特定的 post。这里是调用的在 controller 中的 <tt>edit</tt> action:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def edit
   @post = Post.find(params[:id])
end
</pre>
</div>
<p>再找到了请求的 post, Rails 试图使用 <tt>edit.html.erb</tt> 来显示它:</p>
<div class="code_container">
<pre class="brush: ruby; html-script: true; gutter: false; toolbar: false"><h1>Editing post</h1>
 
<%= render 'form' %>
 
<%= link_to 'Show', @post %> |
<%= link_to 'Back', posts_path %>
</pre>
</div>
<p>就像 <tt>new</tt> action,<tt>edit</tt>  action也使用 <tt>form</tt> partial,这次有所不同,form将会提交一个PUT action到 <tt>PostsController</tt> 并且提交按钮将会显示为 “Update Post”。</p>
<p>提交的form由上面这个视图创建的并且还会调用 controller 中的 <tt>update</tt>  action:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def update
   @post = Post.find(params[:id])
 
   respond_to do |format|
     if @post.update_attributes(params[:post])
       format.html  { redirect_to(@post,
                     :notice => 'Post was successfully updated.') }
       format.json  { head :no_content }
     else
       format.html  { render :action => "edit" }
       format.json  { render :json => @post.errors,
                     :status => :unprocessable_entity }
     end
   end
end
</pre>
</div>
<p>在 <tt>update</tt> action中,Rails 首先使用 <tt>:id</tt> 参数从 edit view(传值到)数据库记录下刚才编辑的内容。当获取了请求的 <tt>post</tt> parameter(一个hash字典)就会 call <tt>update_attributes</tt> 并且 应用 hash 字典的值到相应的记录。如果一切成功,用户会被重定向到 post 的 show 视图。如果期间发生了任何错误,它将回到 edit 视图并(要求)改正他们。</p>
<h4 id="9-12">9.12 删除一个post</h4>
<p>最后,点击一个 <tt>destroy</tt> 链接发送相关的id到 <tt>destroy</tt> 动作:</p>
<div class="code_container">
<pre class="brush: ruby; gutter: false; toolbar: false">def destroy
   @post = Post.find(params[:id])
   @post.destroy
 
   respond_to do |format|
     format.html { redirect_to posts_url }
     format.json { head :no_content }
  

你可能感兴趣的:(Ruby)