Ruby on Rails 学习(三)——15分钟搭建一个博客系统

"15分钟搭建一个博客系统",是Ruby On Rails非常经典Demo练习。rails的创始人DHH当年用一个视频演示了如何在15分钟内搭建一个博客系统,展示除了rails的优雅与灵活,也让更多的人开始关注rails。
之所以能在15分钟内搭建一个博客系统,是与rails的一个原则:“惯例优于设置“(Convention Over Configuration)分不开的。而在搭建过程中,最重要的是使用到了rails中的scaffold(脚手架)功能。
下面,我们来演示如何实现15分钟搭建一个博客系统。

系统环境版本


ubuntu-1404
ruby-2.3.0
rails-5.0.0.1

博客实现功能


  • 可以新建、读取、更新、删除blog
  • 提供blog的评论功能,每个blog下可以有多条评论

系统设计流程演示


(一)实现blog的新建、读取、更新、删除功能

  • 新建工程
$ rails new blog_of_vito
  • 打开工程,新建scaffold(脚手架)
$ rails g scaffold article

我们看到命令行中显示:

      invoke  active_record
      create    db/migrate/20161129044734_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml
      invoke  resource_route
       route    resources :articles
      invoke  scaffold_controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      create      app/views/articles/index.html.erb
      create      app/views/articles/edit.html.erb
      create      app/views/articles/show.html.erb
      create      app/views/articles/new.html.erb
      create      app/views/articles/_form.html.erb
      invoke    test_unit
      create      test/controllers/articles_controller_test.rb
      invoke    helper
      create      app/helpers/articles_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/articles/index.json.jbuilder
      create      app/views/articles/show.json.jbuilder
      create      app/views/articles/_article.json.jbuilder
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/articles.coffee
      invoke    scss
      create      app/assets/stylesheets/articles.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss

短短一行代码,便为我们创建了这么多的功能,其中包括model层(M)、view层(V)和controller层(C),以及迁移(migration)、路由(routing)、helper方法、测试功能等其他一些方法。而在按照这种约定生成的文件中,我们可以发现已经自动生成了很多代码,我们只需要添加部分具体实现功能的代码即可完成整个系统。换句话说,通过rails的约定,scaffold为我们提供了一个框架,通过填增加一些必要的代码,我们便可以轻松地实现我们需要的功能。真的是很方便呐!

  • 为blog添加字段
    blog需要有题目和内容,我们需要在Article模型对应的表上添加这两个字段。
    我们打开/db/migrate/*_create_articles.rb文件,修改为:
def change  
    create_table :articles do |t|    
      t.string :title    
      t.text :text    
      t.timestamps  
    end
end

运行迁移:

$ rails db:migrate

如果rails版本低于5.0,执行命令:

$ rake db:migrate

看到打印信息:

== 20161129044734 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0012s
== 20161129044734 CreateArticles: migrated (0.0012s) ==========================

说明字段已经添加到表中了。

  • 修改articles_controller.rb文件
    打开文件,我们发现scaffold已经为我们生成了indexshowneweditcreateupdatedestroy方法,还生成了两个私有方法:set_articlearticle_params。这些方法基本实现了整个blog的新建、读取、更新、删除的功能。我们只需要告诉controller我们需要使用的字段即可。
    修改article_params方法为:
def article_params
    params.require(:article).permit(:title, :text)
end
  • 修改view文件
    1.修改/app/view/articles/_form.html.erb文件为:
<%= form_for @article do |f| %>  
    <% 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 |message| %>
          <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    <% end %>

    <p>
       <%= f.label :title %><br>
       <%= f.text_field :title %>
    </p>
    <p>
       <%= f.label :text %><br>
       <%= f.text_area :text %>
    </p>
    <p>
       <%= f.submit %>
    </p>
<% end %>

在这个文件中,我们将前几行中的article换成@article,同时添加了blog填写及提交title和text的表单内容。
_form.html.erb是一个局部视图,按照约定,局部视图的文件名以下划线开头。由于在编辑文章页面和新建文章页面很相似,显示表单的代码是相同的,使用局部视图可以去掉两个视图中的重复代码,因此我们直接在这个文件中添加表单即可,而不用分别在new.html.erbedit.html.erb文件中添加相同的代码。
之所以能在两个动作中共用一个 form_for,是因为@article是一个资源,对应于符合 REST 架构的路由,Rails 能自动分辨使用哪个地址和请求方法。
2.修改index.html.erb文件为:

<p id="notice"><%= notice %></p>
<h1>Articles</h1>
<table>
    <thead>
      <tr>
        <th>Title</th><!--new-->
        <th>Text</th><!--new-->
        <th colspan="3"></th>
      </tr>
    </thead>
    <tbody>
      <% @articles.each do |article| %>
        <tr>
          <td><%= article.title %></td><!--new-->
          <td><%= article.text %></td> <!--new-->
          <td><%= link_to 'Show', article %></td>
          <td><%= link_to 'Edit', edit_article_path(article) %></td>
          <td><%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
      <% end %>
    </tbody>
</table>
<br>
<%= link_to 'New Article', new_article_path %>

新加的部分我们使用``标示出来,用来实现显示文章题目和内容的功能。
3.修改show.html.erb文件为:

<p id="notice"><%= notice %></p>
<p>
    <strong>Title:</strong>
    <%= @article.title %>
</p>
<p>
    <strong>Text:</strong>
    <%= @article.text %>
</p>
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

这里添加显示blog的title和text的功能。

  • 修改app/models/article.rb文件
    这里修改model文件,是为了添加一些约束,这里我们要求blog的title不能为空且长度大于3,当不满足要求时页面会报错。
    修改article.rb为;
class Article < ApplicationRecord
    validates :title, presence: true,
              length: { minimum: 3 }
end

这样我们成功建立了一个可以新建、读取查询、更新和删除文章的blog系统,是不是很简单啊!

  • 系统首页效果图:
blog_index.png
blog_show.png

这样,我们的第一部分功能就算是实现了。

(二)添加blog评论功能

这部分我们需要添加blog的评论功能。我们知道对一篇博客评论时我们只需要在对应的博客显示页面下进行评论即可,因此对于评论来说,只需要MC层,而其V层则在/app/views/articles/show.html.erb中实现即可。
因此,我们在这里不使用scaffold来建立评论。

  • 新建评论model层:
$ rails g model comment article_id:integer commenter:string body:text
  • 运行迁移(rails >= 5.0)
$ rails db:migrate
  • 添加评论与文章的对应关系
    一个评论只能对应一篇文章,一篇文章可以又多条评论。
    修改article.rb为:
class Article < ApplicationRecord
    validates :title, presence: true,
              length: { minimum: 3 }
    has_many :comments
end

修改comment.rb为:

class Comment < ApplicationRecord
    belongs_to :article
end
  • 生成comment控制器
$ rails g controller comments
  • 修改comments.rb为:
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
  • /app/views/articles/show.html.erb文件中添加:
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
    <p>
      <strong>Commenter:</strong>
      <%= comment.commenter %>
    </p>
    <p>
      <strong>Comment:</strong>
      <%= comment.body %>
    </p>
<% end %>
<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 %>

这部分代码负责添加评论及评论的显示功能。

  • routes.rb中修改路由为:
resources :articles do
    resources :comments
end

现在,我们的blog系统就已经搭建完成了。
我们来看看添加评论后的效果:

blog_comment.png

总结


我们成功的搭建了一个博客系统。在搭建过程中,我们看到了scaffold的强大功能,短短一行代码为我们实现了很多很多的功能,而这就是rails的魅力。
事实上,我们完全可以自己来实现scaffold的功能,在文中我们将scaffold中的mvc简单地介绍了一下。scaffold为我们提够了足够多的功能,但并非所有的都是我们需要的,在遇到实际问题时,需不需要使用scaffold,还得根据实际需求来决定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容