Padrino 博客开发示例

英文版出处:http://www.padrinorb.com/guides/blog-tutorial

派骓诺

楼主按

拿作者自己的话说:Padrino(谐音:派骓诺)是一款基于Sinatra的优雅的Web应用开发框架,旨在使Web应用的开发变得轻松有趣。

楼主主要是在一台二手笔记本上跑Linux、体验Padrino并对原文进行翻译的。Ruby领域推荐平台是OS X,其次是Linux,如果你对Linux环境感兴趣,可以参考我的配置信息


博客搭建指导

每当我看见天边的绿洲全新的框架,就会想起东方奇诺瓦如何搭博客。我觉得这是让新人迅速上手的最佳方式。本指南将向大家展示如何利用Padrino框架搭建简易博客。在这个过程中,我们将对每一步进行详细的介绍并提供不同相关主题的链接以方便大家学以致用。

学习指南

如果你没功夫跟我磨叽,给你指条道儿,直接从GitHub下载全部示例代码

$ git clone git://github.com/padrino/sample_blog.git

或执行博客指导项目模板,它能够利用模板生成器一步一步地自动建立起博客项目:

$ padrino g project sample_blog --template sampleblog

点击这里了解模板生成器的详细信息。

安装

俗话说:木有蛋/鸡,何来鸡/蛋?为了开发Padrino应用,我们得先有点儿准备吧。显然,我们得先把RubyRubyGems装了;然后,再来安装Padrino框架:

$ gem install padrino

点击这里了解关于安装的详细信息。安装流程一旦完成,所有必需的依赖项也都自动准备就绪,我们现在就可以开始开发自己的博客了。

生成项目

原汤化原食。创建Padrino程序的最佳方式采用Padrino生成器。类似于Rails,Padrino也有一个用来创建包含项目所有必备程序和资源的生成器。Padrino是一个混合型框架(agnostic framework)并支持大量不同的模板、测试、JavaScript和数据库组件。推荐阅读《生成器指南》来获取更详细信息。

就这个示例程序而言,我们将采用ActiveRecord ORM、Haml模板语言、Shoulda测试框架和jQuery类库。基于这些考虑,我们现在来创建这个新项目:

$ padrino g project sample_blog -t shoulda -e haml -c sass -s jquery -d activerecord -b

这行命令将为我们生成Padrino项目的基础文件并打印出生成报告。可以从这里查看这条生成命令的输出信息示例。需要注意的是,-b参数自动指引bundler安装相关的依赖项。现在我们进入新项目文件夹:

$ cd sample_blog

现在,我们已经从终端中进入到项目文件目录了,让我们更近距离地看一下这些可爱的文件吧:

  • Gemfile:确保项目所有gem包依赖项都包含在该文件中!
  • app/app.rb:核心应用程序主要配置文件;
  • config/apps.rb:该文件定义项目要挂载的应用;
  • config/database.rb:顾名思义,定义数据库适配器信息。

除此之外,还生成了一些重要的目录:

  • app/controllers:声明Padrino的路由定义;
  • app/helpers:定义应用的帮助方法;
  • app/views:包含由控制器输出的模板视图;
  • lib:包含项目用到的所有扩展、类库和其它代码;
  • public:保存图片、样式和JavaScript代码文件;
  • test:保存模型和控制器的测试代码;

现在,我们来检查config/database.rb文件以确保数据库连接配置是正确的。截至目前,默认配置对于示例指导来说是可用的。项目将采用存储在db/sample_blog_development.db中Sqlite3数据库。

我们再创建一些简单的路由来演示Padrino的路由系统。进入app/app.rb文件并输入:

# app/app.rb
class SampleBlog::App
  register Padrino::Rendering  
  register Padrino::Helpers
  
  # Add these routes below to the app file...
  get "/" do
    "Hello World!"
  end

  get :about, :map => '/about_us' do
    render :haml, "%p Padrino 博客开发示例"
  end
end

可以看到:第一条路由创建一个字符用来返回应用的根URL;第二条路由将"/about_us"显式映射到由Haml输出的“关于”页面;符号:about用来引用这条路由。

强烈建议亲查看《控制器指南》来对路由系统有一个综合的了解哟!

创建后台管理界面

接下来,为了方便对项目中的数据进行增删改查,我们来建立Padrino后台管理面板。在终端程序中输入:

sample_blog $ padrino g admin
sample_blog $ bundle install

这两行命令将为项目建立管理子程序,并在config/apps.rb文件中声明对自己的挂载。通过这里可以查看该命令的输出结果。

然后,输入下面的指令来创建数据库、运行迁移并运行db/seeds.rb里的种子(seed)任务:

sample_blog $ padrino rake ar:create
sample_blog $ padrino rake ar:migrate
sample_blog $ padrino rake seed

在这个过程中,系统将提示你输入登录管理系统所用的电子邮箱和密码。

如果你想要了解更多关于管理面板的功能和特性,欢迎阅读《管理面板指南》

启动Padrino

Padrino项目建立了、数据库也配置了、管理系统也搭好了,轮到启动Padrino应用服务器的时候了!用内建的Padrino任务来做其实非常简单,只要在终端里执行下面这条命令:

sample_blog $ padrino start

不出意外你应该从终端看到如下输出:

=> Located unlocked Gemfile for development
=> Padrino/0.10.2 has taken the stage development on port 3000
>> Thin web server (v1.2.7 codename This Is Not A Web Server)
>> Maximum connections set to 1024
>> Listening on localhost:3000, CTRL+C to stop

要想了解操作Padrino的终端命令,那就阅读《开发与终端命令》指南。

你的程序现在已经在http://localhost:3000(楼主:Mac和Linux用户可以无比优越地直接简写为0:3000)恭候你的大驾光临了。在浏览器中访问该网址,你可以看到著名的“Hello World!”我们还可以通过下面这行网址进入管理界面:

http://localhost:3000/admin

当然需要登录啰,还记得在执行rake seed命令时写的登录邮箱和密码吧。登录后,你可以尽情探索Padrino的后台管理功能,不过我们将晚一点儿再来介绍更详细的信息。如果你想获取更多关于这方面的资料,可以阅读《管理面板指南》

顺便说一下,Padrino在开发模式中完全支持代码重装。啥,你问这是啥?这就是说你可以让Padrino服务器一边跑一边修改源代码,只需要刷新一下浏览器,光彩立现!建议你专门开一个终端程序来跑Padrino服务器程序。

创建博文

好,程序OK了、布局也定好了,现在我们来实现创建和展示博文的功能。

首先在应用目录中生成模型。和版本0.10.0一样,模型将默认生成到项目的models目录下。如果你觉得不爽,可以用-a参数来自定义你想要存储模型的子目录。

sample_blog $ padrino g model post title:string body:text -a app
=> Located unlocked Gemfile for development
create  app/models/post.rb
create  test/models/post_test.rb
create  db/migrate/002_create_posts.rb

然后在迁移中给博文模型增加一个时间戳:

# db/migrate/002_create_posts.rb
class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.timestamps
    end
  end

  def self.down
    drop_table :posts
  end
end

然后迁移到数据库:

sample_blog $ padrino rake ar:migrate
=> Executing Rake ar:migrate ...
==  CreatePosts: migrating ====================================================
-- create_table("posts", {})
==  CreatePosts: migrated (0.0016s) ===========================================

博文模型便创建好了。然后来创建提供基本展示功能的控制器:

sample_blog $ padrino g controller posts get:index get:show
=> Located unlocked Gemfile for development
create  app/controllers/posts.rb
create  app/helpers/posts_helper.rb
create  app/views/posts
create  test/controllers/posts_controller_test.rb

我们再来添加一些标准路由到控制器里面,比如:index和:show神马的:

# app/controllers/posts.rb
SampleBlog.controllers :posts do
  get :index do
    @posts = Post.all(:order => 'created_at desc')
    render 'posts/index'
  end
  
  get :show, :with => :id do
    @post = Post.find_by_id(params[:id])
    render 'posts/show'
  end
end

上面这个控制器定义了可以通过我们的应用来访问的路由。声明以Http方法get开始,接上一个符号表示动作(Action),放置在一个保存了获取必要对象的变量以及输出视图模板的代码块当中。看上去跟Rails和Sinatra没啥两样,是吧?(博主:好像是吧……)

下一步,为index和show控制器动作分别创建视图:

# app/views/posts/index.haml
- @title = "Welcome"

#posts= partial 'posts/post', :collection => @posts
# app/views/posts/_post.haml
.post
  .title= link_to post.title, url_for(:posts, :show, :id => post)
  .date= time_ago_in_words(post.created_at || Time.now) + '以前'
  .body= simple_format(post.body)
# app/views/posts/show.haml
- @title = @post.title
#show
  .post
    .title= @post.title
    .date= time_ago_in_words(@post.created_at || Time.now) + '以前'
    .body= simple_format(@post.body)    
%p= link_to '显式全部博文', url_for(:posts, :index)

Padrino管理系统使得数据记录的增删改查相当简便自动。通过Padrino管理系统管理博文,只需输入下面这行命令:

sample_blog $ padrino g admin_page post
=> Located unlocked Gemfile for development
create  admin/controllers/posts.rb
create  admin/views/posts/_form.haml
create  admin/views/posts/edit.haml
create  admin/views/posts/index.haml
create  admin/views/posts/new.haml
inject  admin/app.rb

你没关Padrino服务器吧(CTRL + C)?没关就好,来看看管理界面。

用你之前输入的邮箱和密码登录http://localhost:3000/admin

你可以看到有两个Tab,一个是博文,另一个是账户。点击博文那个分页。

只需轻轻点击一下“New”,你便可以开始创建新的记录,页面会罗列出你先前在创建博文模型时设置的所有字段。

注意:确保在创建模型和迁移后运行padrino g admin_page命令。

现在你已经通过管理界面添加了一些博文,访问http://localhost:3000/posts并注意到你创建的博文都会在index动作中显示出来。

你可以通过padrino rake routes命令来显示当前所有定义过的路由:

$ padrino rake routes
    URL                 REQUEST  PATH
    (:about)              GET    /about_us
    (:posts, :index)      GET    /posts
    (:posts, :show)       GET    /posts/show/:id

这对理解控制器和url之间的映射关系很有帮助哦!

在博文中添加账户信息

至此,博文还没有关联上作者信息,这像什么话,不行不行!再来看看博文模型,我们将开始通过增加新的迁移来将作者账户添加到博文中:

sample_blog $ padrino g migration AddAccountToPost account_id:integer
=> Located unlocked Gemfile for development
create  db/migrate/003_add_account_to_post.rb

上述指令创建了一个包含了期望字段的迁移,将account_id附加到博文中。

修改一下迁移文件,将现有博文都指派给系统的第一位用户(现在也就一个用户噻):

# db/migrate/003_add_account_to_post.rb
class AddAccountToPost < ActiveRecord::Migration
  def self.up
    change_table :posts do |t|
      t.integer :account_id
    end
    # and assigns a user to all existing posts
    first_account = Account.first
    Post.all.each { |p| p.update_attribute(:account, first_account) }
  end 
  # ...
end

现在,我们回到博文模型来创建账户关联并增加点儿验证:

# app/models/post.rb
class Post < ActiveRecord::Base
  belongs_to :account
  validates_presence_of :title
  validates_presence_of :body
end

亲,每次修改数据库都要记得迁移人家哦:

sample_blog $ padrino rake ar:migrate
==  AddAccountToPost: migrating ===============================================
-- change_table(:posts)
==  AddAccountToPost: migrated (0.0009s) ====================================== 7:04
=> Executing Rake ar:migrate ...

我们的博文现在已经有了适当的关联和验证,接下来我们需要进入Padrino管理系统做一点儿改动来包含账户和博文。

直奔admin/controllers/posts.rb,将current_account添加到新博文的创建中:

# admin/controllers/posts.rb
Admin.controllers :posts do
# ...
  post :create do
    @post = Post.new(params[:post])
    @post.account = current_account
    if @post.save
      flash[:notice] = '恭喜,博文已成功创建!'
      redirect url(:posts, :edit, :id => @post.id)
    else
      render 'posts/new'
    end
  end
# ...
end

同时还要更新博文的视图来显示作者信息和其它改动:

# app/views/posts/show.haml
- @title = @post.title
#show
  .post
    .title= @post.title
    .date= time_ago_in_words(@post.created_at || Time.now) + ' ago'
    .body= simple_format(@post.body)
    .details
      .author Posted by #{@post.account.email}
%p= link_to '查看全部博文', url_for(:posts, :index)
# app/views/posts/_post.haml
.post
  .title= link_to post.title, url_for(:posts, :show, :id => post)
  .date= time_ago_in_words(post.created_at || Time.now) + ' ago'
  .body= simple_format(post.body)
  .details
    .author 由#{post.account.email}发布

现在来增加一个新用户。到http://localhost:3000/admin,切换到Account分页并创建一条新的账户记录。一旦你有了新的账户,尝试用它登录并添加一些新的博文。猜猜这样会发生什么?这样你就有了多个用户和多篇博文:D

http://localhost:3000/posts看看效果,博文和作者分别全都链接上了。

站点布局

现在,应用已经正确配置并且服务器也跑起来了,我们继续来创建一些基本的样式和布局。

首先,我们为应用创建一个布局。布局是在其路由上扮演内容模板容器角色的文件,它会被用来为应用创建各个结构一致的页面。要想创建布局,只需要简单地想app/views/layouts目录添加文件:

# app/views/layouts/application.haml
!!! Strict
%html
  %head
    %title= [@title, "Padrino 示例博客"].compact.join(" | ")
    = stylesheet_link_tag 'reset', 'application'
    = javascript_include_tag 'jquery', 'application'
    = yield_content :include
  %body
    #header
      %h1 Sample Padrino Blog
      %ul.menu
        %li= link_to '博客', url_for(:posts, :index)
        %li= link_to '关于', url_for(:about)
    #container
      #main= yield
      #sidebar
        - form_tag url_for(:posts, :index), :method => 'get'  do
          Search for:
          = text_field_tag 'query', :value => params[:query]
          = submit_tag 'Search'
        %p Recent Posts
        %ul.bulleted
          %li Item 1 - Lorem ipsum dolorum itsum estem
          %li Item 2 - Lorem ipsum dolorum itsum estem
          %li Item 3 - Lorem ipsum dolorum itsum estem
        %p Categories
        %ul.bulleted
          %li Item 1 - Lorem ipsum dolorum itsum estem
          %li Item 2 - Lorem ipsum dolorum itsum estem
          %li Item 3 - Lorem ipsum dolorum itsum estem
        %p Latest Comments
        %ul.bulleted
          %li Item 1 - Lorem ipsum dolorum itsum estem
          %li Item 2 - Lorem ipsum dolorum itsum estem
          %li Item 3 - Lorem ipsum dolorum itsum estem
    #footer
      Copyright (c) 2009-2013 Padrino

这个布局为博客创建了一个基本结构,并引用了对控制行为和显示而言必要的样式表和JavaScript文件。这个布局应该包含一些假元素,比如假的搜索框和列表项。

然后,我们仅仅需要为演示建立两张样式表。第一张是被艾里克·迈耶斯(Eric Meyers)重置的通用CSS,可以在示例博客仓库找到完整的样式表重置并放到public/stylesheets/reset.css。

第二张是为了博客更酷一点儿的应用样式表,可以从示例博客仓库找到该样式表的完整内容并放置到app/stylesheets/application.sass。

有了布局和样式表,博客终于拿得出手了!让我们访问http://localhost:3000/posts来看看新的界面。

建立RSS订阅功能

在部署应用以前,是不是还漏了点儿啥?对,RSS和Atom订阅。只准用户说他不想看,不准他他看不到!要实现订阅,我们得在博文控制器中为index块添加一个provides选项。下面的代码指定路由需要响应的HTML、RSS和Atom格式:

# app/controllers/posts.rb
SampleBlog.controllers :posts do
...
  get :index, :provides => [:html, :rss, :atom] do
    @posts = Post.all(:order => 'created_at desc')
    render 'posts/index' 
  end
...
end

需要注意的是,这条路由同时也指定渲染引擎(rendering engine)在使用RSS或Atom格式时避免输出。

回到index.haml文件,我们将采用auto_discovery_link_tag帮助方法来生成RSS订阅引用创建器(the RSS feed using builder)。

# app/views/posts/index.haml
- @title = "欢迎"

- content_for :include do
  = feed_tag(:rss, url(:posts, :index, :format => :rss),:title => "RSS")
  = feed_tag(:atom, url(:posts, :index, :format => :atom),:title => "ATOM")

#posts= partial 'posts/post', :collection => @posts

然后添加Atom引用创建器模板:

# app/views/posts/index.atom.builder
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
  xml.title   "Padrino 示例博客"
  xml.link    "rel" => "self", "href" => url_for(:posts, :index)
  xml.id      url_for(:posts, :index)
  xml.updated @posts.first.updated_at.strftime "%Y-%m-%dT%H:%M:%SZ" if @posts.any?
  xml.author  { xml.name "Padrino Team" }

  @posts.each do |post|
    xml.entry do
      xml.title   post.title
      xml.link    "rel" => "alternate", "href" => url_for(:posts, :show, :id => post)
      xml.id      url_for(:posts, :show, :id => post)
      xml.updated post.updated_at.strftime "%Y-%m-%dT%H:%M:%SZ"
      xml.author  { xml.name post.account.email }
      xml.summary post.body
    end
  end
end

还有RSS引用创建器的模板:

# app/views/posts/index.rss.builder
xml.instruct!
xml.rss "version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/" do
  xml.channel do
    xml.title "Padrino Blog"
    xml.description "The fantastic padrino sample blog"
    xml.link url_for(:posts, :index)

    for post in @posts
      xml.item do
        xml.title post.title
        xml.description post.body
        xml.pubDate post.created_at.to_s(:rfc822)
        xml.link url_for(:posts, :show, :id => post)
      end
    end
  end
end

检查一下改动,看看http://localhost:3000/posts是不是已经提供了RSS和Atom订阅。是的,对吧?那就可以开张啦!

部署

丑媳妇终于要见公婆了!用Heroku服务神马的来部署Padrino应用最简单老。

参照《Heroku快速入门指南》,确认你此时已经安装了Git并建立了Heroku账户以及安装了Heroku gem

要部署到Heroku,需要先将应用创建为Git仓库:

sample_blog $ git init
sample_blog $ git add .
sample_blog $ git commit -m "initial commit for app"

以上命令是在初始化Git仓库,并将所有内容都提交进去。然后将应用创建到Heroku:

sample-blog $ heroku create --stack bamboo-ree-1.8.7
sample-blog $ git push heroku master

欧了,你的应用现在就运行在Heroku上了!

运行heroku open命令可以在你的系统默认浏览器里打开网站。

眼目前儿,Padrino默认使用SQLite,但Heroku只认PostgreSQL,咋整?只能将pg添加为依赖项啰:

# Gemfile
group :production do
 gem 'pg'
end

执行下面的命令可以避免在你本地计算机上安装pg gem:

sample-blog $ bundle install --without production

而且有必要为生产配置一下config/database.rb:

# config/database.rb
postgres = URI.parse(ENV['DATABASE_URL'] || '')

ActiveRecord::Base.configurations[:production] = {
  :adapter  => 'postgresql',
  :encoding => 'utf8',
  :database => postgres.path[1..-1], 
  :username => postgres.user,
  :password => postgres.password,
  :host     => postgres.host
}

由于没有shell可以访问padrino rake,我们还得创建一个Rakefile,不过仅需要使用Rakefile生成器:

$ padrino rake gen

自动生成的Rakefile看起来大概是下面这幅样儿:

# Rakefile
require File.dirname(__FILE__) + '/config/boot.rb'
require 'thor'
require 'padrino-core/cli/rake'

PadrinoTasks.init

最后还得调整一下seed.rb:

# db/seeds.rb
email     = "info@padrinorb.com"
password  = "admin"

shell.say ""

account = Account.create(:email => email, 
                         :name => "Foo", 
                         :surname => "Bar", 
                         :password => password, 
                         :password_confirmation => password, 
                         :role => "admin")

if account.valid?
  shell.say "================================================================="
  shell.say "Account has been successfully created, now you can login with:"
  shell.say "================================================================="
  shell.say "   email: #{email}"
  shell.say "   password: #{password}"
  shell.say "================================================================="
else
  shell.say "Sorry but some thing went worng!"
  shell.say ""
  account.errors.full_messages.each { |m| shell.say "   - #{m}" }
end

shell.say ""

上面seed的值你想咋改就咋改,谁也拦不住的。

然后在终端中运行下面的命令:

sample_blog $ git add .
sample_blog $ git commit -m "Added Postgres support"
sample_blog $ git push heroku master

再执行migrations/seeds:

sample_blog $ heroku rake ar:migrate
sample_blog $ heroku rake seed

当当当当,你就看到了:

sample_blog $ heroku rake ar:migrate
(in /disk1/home/slugs/151491_a295681_03f1/mnt)
=> Located locked Gemfile for production
==  CreateAccounts: migrating =================================================
-- create_table("accounts", {})
   -> 0.0185s
==  CreateAccounts: migrated (0.0229s) ========================================

==  CreatePosts: migrating ====================================================
-- create_table("posts", {})
   -> 0.0178s
==  CreatePosts: migrated (0.0218s) ===========================================

==  AddAccountToPost: migrating ===============================================
-- change_table(:posts)
   -> 0.0026s
==  AddAccountToPost: migrated (0.0028s) ======================================

MacBook:sample_blog DAddYE$ heroku rake seed
(in /disk1/home/slugs/151491_7576c59_03f1/mnt)
=> Located locked Gemfile for production

=================================================================
Account has been successfully created, now you can login with:
=================================================================
   email: info@padrinorb.com
   password: admin
=================================================================

然后就可以打开我们部署的应用了:

sample_blog $ heroku open

走起!

posted @ 2013-06-27 11:22 麦机长 阅读(...) 评论(...) 编辑 收藏