<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>rina (angel)</title>
    <link>https://ruby-china.org/rina</link>
    <description>ruby 工程师, 个人博客： http://liuzhen.me</description>
    <language>en-us</language>
    <item>
      <title>1024 节，来测测你是哪款极客程序员？ [集赞有礼品哦]</title>
      <description>&lt;p&gt;&lt;em&gt;1024 程序员节&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;我们向所有极客精神的程序员致敬&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;他们桀骜不驯或谦卑内敛&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;他们沉浸在代码世界中&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;善于用不同角度去思考&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;既不墨守成规，也不安于现状&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;他们拥有分享精神&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;正因为他们大爱着这个世界&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;敲透代码只是表象&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;改变世界才是梦想&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;数字化时代的今天，极客精神的程序员们不断的在改变着这个世界。&lt;/p&gt;

&lt;p&gt;极客之王、“Linux 之父”李纳斯·托沃兹就曾说过：“真正的代码质量意味着让程序员为他们写的代码自豪，参与到编写代码之中并把它当做自己个人的事情，并把这件事情做到极致”。 &lt;/p&gt;

&lt;p&gt;今年 1024 程序员节，该怎么发朋友圈，才能让不善言语的程序员们极客（装逼）指数上升？&lt;/p&gt;

&lt;p&gt;ShowMeBug 推出非常有趣的极客型程序员自测活动，立马测出你的极客咖位！&lt;/p&gt;

&lt;p&gt;识别下方海报二维码，立即开始测试
&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_sgab8kt6t3hogk3mqwtgaxwftqa9b4p2.jpg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;截止目前，我们参与的上千名程序员中，仅有 1 位是 Linus 型程序员，看来 Linus 型程序员还是少数派的，毕竟是金字塔顶端的大神了。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_n4b0b9yral9vyyrzfmvjosvdb6r3yez1.jpg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;测试结果已经在朋友圈刷屏了，平时不发朋友圈的程序员们也晒出自己标签，比以往任何时候都热闹。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_h8ctj75d8wyer8p4ergw1khseve3hw4p.jpeg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;当然啦，除了有意思的测试，ShowMeBug 还为参与测试的程序员朋友送上精品好礼：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_yb9yxp3rnd52dribuct0c6fgfn6dmmzj.jpeg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;奖品领取规则：&lt;/p&gt;

&lt;p&gt;1、将测试结果海报分享至朋友圈，并集齐 1024 个赞（能实现吗？动动你的小脑筋试试吧~）；
2、领取时间：10 月 24 日 晚上 10:24 兑奖；
3、凭借截图添加下方客服微信领取。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_yc0ycjhbl2895nerjmsom983svba1tad.jpeg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;程序员节，当然少不了与技术大神交流的机会，10 月 24 日 20:00 在 ShowMeBug 视频号直播间邀请多位技术大神畅聊「从 Markdown 程序员到技术极客养成记」等话题。&lt;/p&gt;

&lt;p&gt;与大咖互动，抢先一步！快识别下方海报二维码，提前预约，立即锁定！&lt;/p&gt;

&lt;p&gt;&lt;img src="https://showmebugimg.dao42.com/uploads/20211020_kxibcrbbbydncpzwkzf9gt40nd51mvm2.jpeg!/rotate/auto/fw/400" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;最后，预祝大家 1024 程序员节快乐！&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Wed, 20 Oct 2021 17:27:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/41784</link>
      <guid>https://ruby-china.org/topics/41784</guid>
    </item>
    <item>
      <title>如何从零构建个人博客系统</title>
      <description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;这篇文章主要分享博客里涉及的 Ruby, Rails，前端 CSS，JS，ubuntu 系统命令等知识。如果有什么不解的地方可以通过&lt;a href="http://liuzhen.me" rel="nofollow" target="_blank"&gt;http://liuzhen.me&lt;/a&gt;页面下方的二维码扫描加我微信。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ruby 是一种纯粹的面向对象编程语言。它由日本的松本行弘（まつもとゆきひろ/Yukihiro Matsumoto）创建于 1993 年。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ruby on Rails（官方简称为 Rails，亦被简称为 RoR），是一个使用 Ruby 语言写的开源 Web 应用框架，它是严格按照 MVC 结构开发的。它努力使自身保持简单，来使实际的应用开发时的代码更少，使用最少的配置。指南：&lt;a href="https://ruby-china.github.io/rails-guides/" rel="nofollow" target="_blank"&gt;https://ruby-china.github.io/rails-guides/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS 指层叠样式表，你在页面看到的展示效果都是通过 CSS 做出来的，页面的布局，字体大小，颜色，边框，菜单等等。详情可以查看：&lt;a href="http://www.runoob.com/css/css-intro.html" rel="nofollow" target="_blank"&gt;http://www.runoob.com/css/css-intro.html&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JS 是属于网络的脚本语言，能做的事太多了，像我博客里的相册功能，时间线都是 JS 做出来的效果。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安装Rails环境"&gt;安装 Rails 环境&lt;/h2&gt;
&lt;p&gt;你可以通过搜索 &lt;code&gt;Mac/windows/ubuntu install rails&lt;/code&gt; 来找到相关文档，这里提供 ubuntu 16.04 版本的安装文档：&lt;a href="https://gorails.com/setup/ubuntu/16.04" rel="nofollow" target="_blank"&gt;https://gorails.com/setup/ubuntu/16.04&lt;/a&gt; , Mac 的安装文档：&lt;a href="https://ruby-china.org/wiki/mac-nginx-passenger-rails" rel="nofollow" target="_blank"&gt;https://ruby-china.org/wiki/mac-nginx-passenger-rails&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="创建一个Rails项目"&gt;创建一个 Rails 项目&lt;/h2&gt;
&lt;p&gt;安装好 Rails 环境之后，你可以创建一个 Rails 项目了，如果你从来没用过 Rails，可以先用 15 分钟学习一下 &lt;a href="https://ruby-china.github.io/rails-guides/getting_started.html" rel="nofollow" target="_blank" title=""&gt;Rails 入门&lt;/a&gt;, 了解 Rails MVC 结构。&lt;/p&gt;

&lt;p&gt;如果你对 Rails 有一定的了解，可以按照这个模版 &lt;a href="https://github.com/80percent/rails-template" rel="nofollow" target="_blank"&gt;https://github.com/80percent/rails-template&lt;/a&gt; 提供的操作步骤，创建一个 Rails 项目，使用这个模版创建 Rails 项目的好处是，这个模版相当于一个全家桶，预先添加一个项目经常需要使用的 Gem 包，发布需要的 puma, mina, monit, nginx 配置文件，关于这几个东西是什么，有什么用后面会讲到。&lt;/p&gt;

&lt;p&gt;启动 Rails&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ rails s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;访问 &lt;code&gt;localhost:3000&lt;/code&gt; 就能看到 hello world 页面了。&lt;/p&gt;
&lt;h2 id="创建数据模型"&gt;创建数据模型&lt;/h2&gt;
&lt;p&gt;我的博客在设计之初只想要文章，相册，简历这几个功能，这三个功能比较相似，都有标题，内容和可有可无的描述。所以我就用了单表继承，建了个 base 表。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rails g model Base title:string content:text subtitle:string type:string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;type 字段就是用于单表继承。&lt;/p&gt;

&lt;p&gt;执行完这条命令之后，你会看到 &lt;code&gt;db/migrate/xxxx_create_bases.rb&lt;/code&gt; 多了一个这样的文件，里面的内容是：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CreateBases &amp;lt; ActiveRecord::Migration[5.1]
  def change
    create_table :bases do |t|
      t.string :title
      t.string :subtitle
      t.text :content
      t.string :type
      t.timestamps
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;t.timestamps 是时间戳，系统会自动在这个表里面加上 &lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;updated_at&lt;/code&gt; 两个字段。&lt;/p&gt;

&lt;p&gt;添加完之后，需要把做一下数据迁移，我一开始学 rails 的时候对 &lt;code&gt;数据迁移&lt;/code&gt; 这个词很不理解。其实数据迁移的意思就是，我们现在通过命令创建了个数据表的文件，但是这个文件没有被执行，不执行数据库里就还没有这张表，只有在执行了 &lt;code&gt;rails db:migrate&lt;/code&gt; 之后，rails 才在数据库里把这张表给加上，这个操作就叫做 数据迁移。&lt;/p&gt;

&lt;p&gt;创建完了 Base 表，现在就要创建文章表了 Article, 我们需要添加一个 &lt;code&gt;app/models/article.rb&lt;/code&gt; 文件，写上：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Article &amp;lt; Base
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 Article 继承了 Base, 所以就拥有了 Base 的所有字段了。&lt;/p&gt;

&lt;p&gt;你可以通过 &lt;code&gt;rails c&lt;/code&gt; 从控制台输入 &lt;code&gt;Article.new&lt;/code&gt; 可以看到：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb(main):006:0* Article.new
=&amp;gt; #&amp;lt;Article id: nil, title: nil, subtitle: nil, content: nil, type: "Article", created_at: nil, updated_at: nil&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;type 字段自动就是 Article, 这是 Rails 的一个特性，单表继承。&lt;/p&gt;

&lt;p&gt;输入&lt;code&gt;Article.all&lt;/code&gt;, 看到的 sql 语句实际是从 bases 里查询 type 为 Article 的所以记录。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;irb(main):007:0&amp;gt; Article.all
Article Load (127.0ms)  SELECT  "bases".* FROM "bases" WHERE "bases"."type" IN ('Article') LIMIT $1  [["LIMIT", 11]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;相册表&lt;code&gt;Photo&lt;/code&gt;，简历表&lt;code&gt;Resume&lt;/code&gt;和&lt;code&gt;Article&lt;/code&gt;的创建方式相同。&lt;/p&gt;

&lt;p&gt;表创建好了，我们就可以创建&lt;code&gt;Controller&lt;/code&gt;了，&lt;code&gt;Controller&lt;/code&gt;需要区分前端和后端，前端就是提供给用户查询的，后台是提供自己添加，更新，删除操作的。另外后台因为是管理的地方所以不能让所有人都访问，所以需要设置成通过用户名和密码登录。这样别人就无法访问你的后台。&lt;/p&gt;
&lt;h2 id="后端设计"&gt;后端设计&lt;/h2&gt;
&lt;p&gt;为了与前台有所区分，所以需要加一下命名空间：这里设置成 &lt;code&gt;admin&lt;/code&gt;. 先在 &lt;code&gt;config/routes.rb&lt;/code&gt; 里添加路由，&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails.application.routes.draw do
  namespace :admin do
    root 'dashboard#index', as: 'root'
    resources :articles
    resources :photos
    resource :resume, only: [:edit, :update]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;root 'dashboard#index', as: 'root'&lt;/code&gt; 设置后台的&lt;code&gt;root&lt;/code&gt;路由。使用 &lt;code&gt;rails routes&lt;/code&gt; 命令可以查看具体的路由信息。&lt;/p&gt;
&lt;h3 id="控制器"&gt;控制器&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;controllers&lt;/code&gt; 目录下添加&lt;code&gt;admin&lt;/code&gt;目录，这个目录下用于存放所有的后台文件，后台添加一个 &lt;code&gt;app/controllers/admin/base_controller.rb&lt;/code&gt; 文件，继承了 &lt;code&gt;ApplicationController&lt;/code&gt;, 这么做是为了&lt;code&gt;admin&lt;/code&gt;下的所有&lt;code&gt;controller&lt;/code&gt;继承 &lt;code&gt;Admin::BaseController&lt;/code&gt; 后，用户访问后端链接就会先校验当前用户是否登录，如果没有登录就跳转到登录页面。
代码如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Admin::BaseController &amp;lt; ApplicationController
  layout 'admin'
  before_action :authenticate_user
  def authenticate_user
    unless session[:login]
      redirect_to new_session_path
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为&lt;code&gt;article&lt;/code&gt;, &lt;code&gt;photo&lt;/code&gt;, &lt;code&gt;resume&lt;/code&gt;这几个功能比较相似，所以我只讲一下&lt;code&gt;article&lt;/code&gt;控制器：&lt;code&gt;app/controllers/admin/articles_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;代码：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Admin::ArticlesController &amp;lt; Admin::BaseController
  def index
    @articles = Article.all.order(created_at: 'DESC').page(params[:page])
  end
  def new
    @article = Article.new
  end
  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to admin_articles_path
    else
      render 'new'
    end
  end
  def edit
    @article = Article.find(params[:id])
  end
  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      flash[:notice] = '更新成功'
      redirect_to admin_articles_path
    else
      render 'edit'
    end
  end
  def destroy
    @article = Article.find(params[:id])
    if @article.destroy
      flash[:notice] = '删除成功'
    else
      flash[:notice] = "删除失败, 原因: #{@article.errors.messages.to_s}"
    end
  end
  private
  def article_params
    params.require(:article).permit(:title, :subtitle, :content)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;控制台里面很简单，就是增，删，改，查。需要注意的就是&lt;code&gt;redirect_to&lt;/code&gt;, &lt;code&gt;render&lt;/code&gt;的区别，什么时候要用&lt;code&gt;render&lt;/code&gt;, 什么时候用&lt;code&gt;redirect_to&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;render&lt;/code&gt; 是指直接熏染某个页面。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;redirect_to&lt;/code&gt; 是指告诉浏览器，让浏览器再重新发送一个指定路由的请求操作。&lt;/p&gt;

&lt;p&gt;如：&lt;code&gt;create action&lt;/code&gt; 里写到如果保存成功就 &lt;code&gt;redirect_to admin_articles_path&lt;/code&gt;, 如果失败就 &lt;code&gt;render 'new'&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;假如保存成功，就会告诉浏览器，让浏览器再向服务器发送一个&lt;code&gt;admin/articles&lt;/code&gt;路由请求，然后进入&lt;code&gt;index action&lt;/code&gt;里，查询所有&lt;code&gt;Action&lt;/code&gt;记录，再熏染&lt;code&gt;index.html&lt;/code&gt;页面，返回给浏览器。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;假如保存失败，就用用户填写的&lt;a href="/article" class="user-mention" title="@article"&gt;&lt;i&gt;@&lt;/i&gt;article&lt;/a&gt;信息熏染&lt;code&gt;new.html&lt;/code&gt;页面，并用 flash 里的信息，告诉用户提交失败的原因，如果失败后用 &lt;code&gt;redirect_to new_admin_articles_path&lt;/code&gt;，也能跳转到&lt;code&gt;new&lt;/code&gt;页面，但是用户提交的信息就没有了。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="view"&gt;view&lt;/h3&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.row
  .offset-md-2.col-md-8
    = simple_form_for [:admin, @article] do |f|
      = f.error_notification
      = f.input :title
      = f.input :subtitle
      = f.text_area :content, id: 'editor_content', class: 'simditor', autofocus: true
      = f.submit '提交', class: 'btn btn-primary'
      = link_to '取消', admin_articles_path
javascript:
  new Simditor({
    textarea: $('#editor_content'),
    toolbar: ['title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale', 'color', '|', 'ol', 'ul', '|', 'blockquote', 'code', 'table', 'link', 'image', 'hr', 'indent', 'outdent', 'alignment']
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个有点需要讲的是编辑器使用了&lt;code&gt;simditor&lt;/code&gt;插件，具体要加哪些信息可以看一下这个文档：&lt;a href="http://simditor.tower.im/" rel="nofollow" target="_blank"&gt;http://simditor.tower.im/&lt;/a&gt;,  但是要支持上传图片功能需要在 admin 下添加一条路由：&lt;code&gt;post '/upload', to: 'photos#upload'&lt;/code&gt;, 在&lt;code&gt;photos controller&lt;/code&gt;里添加一个&lt;code&gt;upload action&lt;/code&gt;，把上传的图片保存到数据库。&lt;/p&gt;
&lt;h3 id="前端设计"&gt;前端设计&lt;/h3&gt;
&lt;p&gt;前端的&lt;code&gt;controller&lt;/code&gt;继承&lt;code&gt;ApplicationController&lt;/code&gt;，前端的因为只设计到查询，所以添加路由的时候加上&lt;code&gt;only&lt;/code&gt;, 如：&lt;code&gt;resources :articles, only: [:index, :show]&lt;/code&gt;, 就只添加两条路由，如果不加&lt;code&gt;only&lt;/code&gt;默认会创建 7 条路由。&lt;/p&gt;

&lt;p&gt;前端功能主要就涉及到 css.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/9fdb0c33-98a9-4685-9a90-2ea04206570a.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;css 调试步骤：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;右击选择'检查'，就能打开控制台，在控制台处，通过点击（2) 处的图标，可以选择页面上任意节点，选择后 (3) 处会显示这个节点所对应的 CSS 样式。同样在 style 处可以通过添加和注释 css 来对页面样式进行调试。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;样式这里涉及的东西太多，我不一一讲解，只讲一些我认为值得讲一讲的知识点。如果想学习更多的 css 样式知识，可以在文章开头处提供的文档查看学习。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;文章的展示对字体，间距，背景，颜色等等都要求很高，如果设计的不好，文章看久了就容易累，而且容易给别人一种不想去看的感觉。如果间距很窄，一大段落全是文字，就给人一种很不舒服的感觉。如果你对这些信息了解不多，不知道把这些值设置成多少比较好，也不要担心，找一个你觉得文字展示效果看起来很舒服的网站，打开他的控制台，看一下这个网站上这些信息设置的值是多少，跟着一样设置就行了。具体的细节可以再另做调整。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;博客的页面底部用的 fa 字体，在&lt;code&gt;gemfile&lt;/code&gt;里添加 &lt;code&gt;font-awesome-sass&lt;/code&gt; 后，就能展示出这些字体图标。但是目前的字体中没有支付宝的字体图标，你先不要看代码，想一想，如果是你，你要怎么实现一个跟 fa 字体相同效果的图标，这个图标带有 hover 效果，当鼠标放上去的时候背景变成了蓝色。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/47090b49-c883-4d1e-89a7-4940a00e968b.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;我的实现方法：&lt;/p&gt;

&lt;p&gt;一开始我想的是用一个黑白图片代替，弄完之后我发现 hover 效果无法实现。于是我就用一个背景透明只有一个支字的图片代替，设置 border-radius，background-color 和字体达成一致效果，当鼠标放上去的时候就改变 background-color: #0085A1;&lt;/p&gt;

&lt;p&gt;代码：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;footer .fa-alipay {
    border-radius: 50%;
    margin-bottom: 4px;
    background-color: #222529;
    width: 41px;
}
footer .fa-alipay:hover {
    background-color: #0085A1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;调试页面上关于&lt;code&gt;hover&lt;/code&gt;,&lt;code&gt;visited&lt;/code&gt;, &lt;code&gt;focus&lt;/code&gt;, &lt;code&gt;active&lt;/code&gt;效果，可以像图片中勾选来查看相应的样式效果。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/cafa75fb-d1eb-4245-a9d1-483d682376b4.png!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="时间线"&gt;时间线&lt;/h2&gt;
&lt;p&gt;时间线是用的一个 js 库，&lt;a href="https://github.com/RyanFitzgerald/vertical-timeline" rel="nofollow" target="_blank"&gt;https://github.com/RyanFitzgerald/vertical-timeline&lt;/a&gt;, 具体可以查看文档。值得说一下的是，一开始看到这个时间线的效果是在一个网站看到的。然后我通过页面控制台，看到里面 class 名称命名很规范，所以感觉是个 js 库，直接在 google 搜索 &lt;code&gt;cd-timeline-block&lt;/code&gt; 第一个结果就是这个库的信息。除了这种方式，还可以通过控制台的&lt;code&gt;Sources&lt;/code&gt;查看&lt;code&gt;assets&lt;/code&gt;文件信息，一般都是经常压缩的，但是有些外部库是有注释的，会写上这个是来自哪个库之类的信息。不过最简单快速的办法还是用 google 搜索来的快一点。如果你搜的 class 名字没有找到相应的信息，可以换个 class 名字试试。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/4be63074-82ab-44ac-9d91-1963f856edd9.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;另外一个要说的是，这个 JS 库里的一个 js 文件&lt;code&gt;main.js&lt;/code&gt;, 与 turbolink 一起加载，没生效，加载的时候就没被执行，然后我就把它用&lt;code&gt;$(document).on 'turbolinks:load'&lt;/code&gt;, 加载就好了。&lt;/p&gt;
&lt;h2 id="相册"&gt;相册&lt;/h2&gt;
&lt;p&gt;博客里我最喜欢的就是这个相册功能了，当初也是看了这个翻书的效果，我才有重写博客的冲动。看到这个 js 库是在&lt;code&gt;github Trending&lt;/code&gt;上，这上面会推荐 github 上比较火的项目。这个库的地址：&lt;a href="http://www.turnjs.com" rel="nofollow" target="_blank"&gt;http://www.turnjs.com&lt;/a&gt;, 这里面提供了几个 demo. 这个 turnjs 用的 &lt;code&gt;yepnope&lt;/code&gt; 加载 js，这么加载是因为，有些内容需要在其他文件加载之后去执行。但是有个问题是在生产环境这些 js 文件都是被转译了的。所以直接在&lt;code&gt;yepnope&lt;/code&gt;里面写上文件名，在生产环境上就会找不到对应的文件。对于这个我没有想到特别好的处理办法，就用  &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$('head').append('&amp;lt;%= javascript_include_tag 'turn.min.js' %&amp;gt;')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来加载文件，然后再执行&lt;code&gt;yepnope({complete: loadApp})&lt;/code&gt;。如果你有更好的办法可以交流一下。&lt;/p&gt;
&lt;h2 id="其他知识点"&gt;其他知识点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;效果支持手机端页面需要加上：&lt;code&gt;meta width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;前端和后端的 JS, CSS 尽量分开，这样加载速度会快一些&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用的外部库最好重新命名成可读名称，不然时间长了你就不知道这个库是干什么的了。比如我用了 timeline 的 JS 库，里面有个 main.js 的文件，我就把它重命名为 timeline-main.js, 这样不需要再加注释来说明这个文件是做什么的了。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="发布"&gt;发布&lt;/h2&gt;
&lt;p&gt;发布需要在服务器上安装好 rails 后，配置&lt;code&gt;nginx.conf&lt;/code&gt;，一般放在&lt;code&gt;/etc/nginx/conf.d/xxx.conf&lt;/code&gt;文件。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;puma.rb&lt;/code&gt;，&lt;code&gt;deploy.rb&lt;/code&gt; 配置文件是 mina 部署的相关配置信息，具体操作了什么可以通过&lt;code&gt;bundle exec mina deploy -v&lt;/code&gt;来查看：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundle exec mina deploy -v
-----&amp;gt; Creating a temporary build path
-----&amp;gt; Server: liuzhen.me
-----&amp;gt; Path: /home/ruby/RBlog
       $ echo "-----&amp;gt; Branch: master"
-----&amp;gt; Branch: master
-----&amp;gt; Using RVM environment "2.3.1"
-----&amp;gt; Quiet sidekiq (stop accepting new work)
-----&amp;gt; Fetching new git commits
       $ (cd "/home/ruby/RBlog/scm" &amp;amp;&amp;amp; git fetch "https://github.com/liuzhenangel/RBlog.git" "master:master" --force)
-----&amp;gt; Using git branch 'master'
       $ git clone "/home/ruby/RBlog/scm" . --recursive --branch "master"
       Cloning into '.'...
       done.
-----&amp;gt; Using this git commit
       $ git rev-parse HEAD &amp;gt; .mina_git_revision
       $ git --no-pager log --format="%aN (%h):%n&amp;gt; %s" -n 1
       liuzhenangel (eb06b54):
       &amp;gt; update timeline
       $ rm -rf .git
-----&amp;gt; Symlinking shared paths
-----&amp;gt; Installing gem dependencies using Bundler
       $ bundle install --without development test --path "vendor/bundle" --deployment
-----&amp;gt; DB migrations unchanged; skipping DB migration
-----&amp;gt; Skipping asset precompilation
-----&amp;gt; Cleaning up old releases (keeping 5)
-----&amp;gt; Deploy finished
-----&amp;gt; Building
-----&amp;gt; Moving build to /home/ruby/RBlog/releases/41
-----&amp;gt; Build finished
-----&amp;gt; Launching
-----&amp;gt; Updating the /home/ruby/RBlog/current symlink
-----&amp;gt; Restart Puma -- hard...
-----&amp;gt; Stopping Puma...
-----&amp;gt; Starting Puma...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从这些日志信息可以看出，首先会根据你配置的服务器的域名和用户名 ssh 到服务器上，加载 ruby 环境，从 github 拉取最新代码，安装 gem 包，如果 css, js, 图片有更新就重新编译压缩 js, css, 图片，执行 &lt;code&gt;db:migrate&lt;/code&gt; 数据迁移，首次发布还会执行&lt;code&gt;rails db:create&lt;/code&gt;来创建数据库。然后重启 puma.&lt;/p&gt;
&lt;h2 id="为什么要nginx，puma"&gt;为什么要 nginx，puma&lt;/h2&gt;
&lt;p&gt;nginx 相当于一个代理，当你在浏览器输入：&lt;code&gt;http://liuzhen.me&lt;/code&gt; 的时候，先通过 DNS 找到这个域名对应的 IP，然后通过路由到达 IP 所在的服务器上，服务器发现用户请求的是 liuzhen.me，然后 nginx 就根据配置文件里配置的 liuzhen.me 找到对应的项目，这个 Rails 项目是由 puma 启动的，然后 nginx 就把这个事交给 puma, puma 收到后就根据路由去到对应的 controller，然后返回对应的页面给到浏览器。&lt;/p&gt;
&lt;h2 id="monit 是什么"&gt;monit 是什么&lt;/h2&gt;
&lt;p&gt;没有 monit 也能发布成功，但是有时候你的 puma 可能异常关掉了，如果有 monit 的话，就能时刻监听这个进程是不是启动状态，一旦关闭了，就重新启动。&lt;/p&gt;

&lt;p&gt;博客地址：&lt;a href="http://liuzhen.me" rel="nofollow" target="_blank"&gt;http://liuzhen.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;博客代码：&lt;a href="https://github.com/liuzhenangel/RBlog" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/RBlog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;原文来源： &lt;a href="http://liuzhen.me/articles/16" rel="nofollow" target="_blank"&gt;http://liuzhen.me/articles/16&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Sat, 23 Dec 2017 00:26:34 +0800</pubDate>
      <link>https://ruby-china.org/topics/34759</link>
      <guid>https://ruby-china.org/topics/34759</guid>
    </item>
    <item>
      <title>辞旧迎新之际, 我给博客换了新装</title>
      <description>&lt;p&gt;2015 年 3 月份我用 Rails 写了第一个比较完整的项目——首个博客系统，现在回过头来看，觉得很多地方都写的比较烂，今年年初的时候我打算重构自己的博客系统，从一开始的想法到完成整件事，经历了长达一年的时间，原因只有一个——懒。&lt;/p&gt;

&lt;p&gt;这个博客的诞生是因为平时在浏览其他网站及关注一些 js 库时发现一些特别喜欢的东西，所以才给了我做这件事的动力。其实做完这个项目真正花费的时间并不多，比较难的是要让自己愿意来做这件事。&lt;/p&gt;

&lt;p&gt;整个项目做下来，对我来说，最难的不是技术实现，而是为博客每个主题找到合适的背景图片，简直就是大海捞针。别人给我推荐了这个 &lt;a href="https://unsplash.com" rel="nofollow" target="_blank" title=""&gt;图片库&lt;/a&gt;，经过长时间的寻找，终于找到了几张让我比较满意的的图片。这个工具不错，有需要的可以收藏一下。&lt;/p&gt;

&lt;p&gt;新的博客系统主要功能有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;后端：数据统计，后台文章管理，相册管理，个人简历管理&lt;/li&gt;
&lt;li&gt;前端：文章列表，相册展示，时间线等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="Demo"&gt;Demo&lt;/h2&gt;
&lt;p&gt;项目 Demo 请访问：&lt;a href="http://liuzhen.me" rel="nofollow" target="_blank"&gt;http://liuzhen.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目 github 代码：&lt;a href="https://github.com/liuzhenangel/RBlog" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/RBlog&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="核心技术框架"&gt;核心技术框架&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ruby on Rails 5.1.4&lt;/li&gt;
&lt;li&gt;bootstrap 4&lt;/li&gt;
&lt;li&gt;font-awesome&lt;/li&gt;
&lt;li&gt;figaro&lt;/li&gt;
&lt;li&gt;postgres&lt;/li&gt;
&lt;li&gt;slim&lt;/li&gt;
&lt;li&gt;high_voltage&lt;/li&gt;
&lt;li&gt;carriewave &amp;amp; upyun&lt;/li&gt;
&lt;li&gt;sidekiq&lt;/li&gt;
&lt;li&gt;kaminari&lt;/li&gt;
&lt;li&gt;mina&lt;/li&gt;
&lt;li&gt;puma&lt;/li&gt;
&lt;li&gt;lograge&lt;/li&gt;
&lt;li&gt;simditor&lt;/li&gt;
&lt;li&gt;turn.js&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="开发环境准备"&gt;开发环境准备&lt;/h2&gt;
&lt;p&gt;第一步，安装项目依赖&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ bundle install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;第二步，启动服务&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ rails s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;第三步，浏览器访问：&lt;a href="http://localhost:3000" rel="nofollow" target="_blank"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;结束。&lt;/p&gt;
&lt;h2 id="如何发布?"&gt;如何发布？&lt;/h2&gt;
&lt;p&gt;第一步，配置 nginx&lt;/p&gt;

&lt;p&gt;先根据项目里的 config/deploy/production.rb, /config/deploy.rb, config/puma.rb, /config/nigix.conf 文件，修改其中的配置，然后将 /config/nigix.conf 文件复制到你的服务器上 nginx 所在目录的 /etc/nginx/conf.d 目录下，命名为 xxx.conf 的文件。然后重启 nginx.&lt;/p&gt;

&lt;p&gt;第二步，在服务器上初始化&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ mina setup&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;第三步，发布&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ mina deploy&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="学习参考资料"&gt;学习参考资料&lt;/h2&gt;
&lt;p&gt;Rails 文档：&lt;a href="http://edgeguides.rubyonrails.org/api_app.html" rel="nofollow" target="_blank"&gt;http://edgeguides.rubyonrails.org/api_app.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;使用模板创建 Rails 项目：&lt;a href="https://github.com/80percent/rails-template" rel="nofollow" target="_blank"&gt;https://github.com/80percent/rails-template&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ubuntu16.04 安装 rails: &lt;a href="https://gorails.com/setup/ubuntu/16.04" rel="nofollow" target="_blank"&gt;https://gorails.com/setup/ubuntu/16.04&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;simditor 编辑器：&lt;a href="http://simditor.tower.im/" rel="nofollow" target="_blank"&gt;http://simditor.tower.im/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;startbootstrap-clean-blog 前端样式：&lt;a href="https://startbootstrap.com/template-overviews/clean-blog/" rel="nofollow" target="_blank"&gt;https://startbootstrap.com/template-overviews/clean-blog/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;sb-admin 前端样式：&lt;a href="https://startbootstrap.com/template-overviews/sb-admin/" rel="nofollow" target="_blank"&gt;https://startbootstrap.com/template-overviews/sb-admin/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;turnjs 前端样式：&lt;a href="http://www.turnjs.com" rel="nofollow" target="_blank"&gt;http://www.turnjs.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;timeline 前端样式：&lt;a href="https://github.com/RyanFitzgerald/vertical-timeline" rel="nofollow" target="_blank"&gt;https://github.com/RyanFitzgerald/vertical-timeline&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;图片库：&lt;a href="https://unsplash.com" rel="nofollow" target="_blank"&gt;https://unsplash.com&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="引荐 Vue.js 项目"&gt;引荐 Vue.js 项目&lt;/h2&gt;
&lt;p&gt;项目 Demo 请访问：&lt;a href="http://v2ex.liuzhen.me/" rel="nofollow" target="_blank"&gt;http://v2ex.liuzhen.me/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目代码：&lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/v2ex_frontend&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="引荐 React.js 项目"&gt;引荐 React.js 项目&lt;/h2&gt;
&lt;p&gt;项目 Demo 请访问：&lt;a href="http://ruby-china.liuzhen.me/" rel="nofollow" target="_blank"&gt;http://ruby-china.liuzhen.me/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目代码：&lt;a href="https://github.com/liuzhenangel/react-ruby-china" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/react-ruby-china&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Mon, 18 Dec 2017 10:20:57 +0800</pubDate>
      <link>https://ruby-china.org/topics/34722</link>
      <guid>https://ruby-china.org/topics/34722</guid>
    </item>
    <item>
      <title>GitHub 个人账户如何删除 Billing 账号？</title>
      <description>&lt;p&gt;github 帮助文档只有组织账户下删除的方式：&lt;a href="https://help.github.com/articles/removing-a-billing-manager-from-your-organization/" rel="nofollow" target="_blank"&gt;https://help.github.com/articles/removing-a-billing-manager-from-your-organization/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;个人账户绑定账号后没有删除接口。。。。
&lt;img src="https://l.ruby-china.com/photo/2017/b775c150-0449-4a99-868b-2b24d05fac1d.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;有没有其他方式删除？&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Tue, 21 Nov 2017 11:38:51 +0800</pubDate>
      <link>https://ruby-china.org/topics/34602</link>
      <guid>https://ruby-china.org/topics/34602</guid>
    </item>
    <item>
      <title>发现个关注统计数字的 Bug</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/7e1cd4db-3a87-4e48-91d2-2c21cc15edcb.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Thu, 27 Apr 2017 12:03:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/32885</link>
      <guid>https://ruby-china.org/topics/32885</guid>
    </item>
    <item>
      <title>使用金数据被感动到了</title>
      <description>&lt;p&gt;事情是这样的。&lt;/p&gt;

&lt;p&gt;有个问卷调查的需求，一开始用的问卷星，现在想把数据集成到自己平台上。因为前段时间一直被安利金数据很好用，于是我在 12 月底注册了个账号，想看看能不能直接把结果弄过来，结果在 设置 -&amp;gt;  结果分享 看到了这个。 
&lt;img src="https://l.ruby-china.com/photo/2017/b78d40c49fd018f550bc07ccdd15b880.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;然后直接在项目里加了一行：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;iframe.embed-responsive-item src="&lt;a href="https://jinshuju.net/f/5PnXLt/xxx" rel="nofollow" target="_blank"&gt;https://jinshuju.net/f/5PnXLt/xxx&lt;/a&gt;" id='survey_iframe' 就可以完美结合了。是不是觉得 so easy!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;当时看到免费版的提交量是 50 条/月，为了满足我的好奇心，于是在 12 月 30 号，我成功把 50 条都用完了。我当时想着，反正马上就 1 号了。然而到了 1 月 3 号  还是显示提交量用完了。
于是我给金数据 HR 发了封邮件，结果收到了这个，没想到还关注了我的 &lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank" title=""&gt;Vue.js 前端项目&lt;/a&gt;，好感动啊。决定成为金数据终身粉了，有木有。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/61f0f62a162b9451d1864659936d533a.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2017/d134135ea3a3f88852a9b20e84865a00.png!large" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Tue, 03 Jan 2017 16:19:22 +0800</pubDate>
      <link>https://ruby-china.org/topics/32048</link>
      <guid>https://ruby-china.org/topics/32048</guid>
    </item>
    <item>
      <title>V2EX 克隆项目升级 Vue.js 1.x to 2.0</title>
      <description>&lt;p&gt;Demo: &lt;a href="http://v2ex.liuzhen.me/" rel="nofollow" target="_blank"&gt;http://v2ex.liuzhen.me/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目地址：&lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/v2ex_frontend&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目升级更新详情：&lt;a href="https://github.com/liuzhenangel/v2ex_frontend/commit/8bc0a8d87728e9e08f9207ebe0ff6e806cc704f2" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/v2ex_frontend/commit/8bc0a8d87728e9e08f9207ebe0ff6e806cc704f2&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="升级步骤:"&gt;升级步骤：&lt;/h3&gt;
&lt;p&gt;第一步，安装 &lt;a href="https://github.com/vuejs/vue-migration-helper" rel="nofollow" target="_blank" title=""&gt;vue-migration-helper&lt;/a&gt; CLI 工具，以帮助从 Vue 1.x 迁移到 2.0。它扫描文件以获取 Vue 特定的代码，并在找到过时的模式时提供详细的警告。&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt; git://github.com/vuejs/vue-migration-helper.git

&lt;span class="c"&gt;# navigate to a Vue 1.x project directory&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;path/to/my-vue-project

&lt;span class="c"&gt;# scan all files in the current directory&lt;/span&gt;
vue-migration-helper
&lt;span class="c"&gt;# scan all files in specific sub-directories&lt;/span&gt;
vue-migration-helper src folder-a folder-b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二步，根据提示信息修改文件中对应的地方。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.imgur.com/aHh5TfR.png" title="" alt="Screenshot"&gt;&lt;/p&gt;

&lt;p&gt;另：v2ex_frontend 项目 1.0 引用了 &lt;code&gt;vue-paginate&lt;/code&gt;, 这个 package 不支持 Vue.js 2.0, 目前已经删除使用。&lt;/p&gt;
&lt;h3 id="2.0 相关文档"&gt;2.0 相关文档&lt;/h3&gt;
&lt;p&gt;vue.js 2.0 中文文档：&lt;a href="http://vuefe.cn/guide/" rel="nofollow" target="_blank"&gt;http://vuefe.cn/guide/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vue.js 2.0 英文文档：&lt;a href="http://rc.vuejs.org/guide/installation.html" rel="nofollow" target="_blank"&gt;http://rc.vuejs.org/guide/installation.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vue-router 2.0 文档：&lt;a href="http://router.vuejs.org" rel="nofollow" target="_blank"&gt;http://router.vuejs.org&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Sat, 15 Oct 2016 13:45:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/31331</link>
      <guid>https://ruby-china.org/topics/31331</guid>
    </item>
    <item>
      <title>基于 React.js + Redux + Bootstrap 的 Ruby China 示例</title>
      <description>&lt;p&gt;最近在学习前端的各大流行框架，主要学习了 Vue.js 和 React.js, 前段时间用 Vue.js + uikit 实现了 V2EX 的克隆版本，最近又用 React.js + redux + bootstrap 实现了 RubyChina 的克隆版本，两个项目都支持响应式布局。不得不说这是学习新知识的一个有效途径。这两个项目都比较合适学习 Vue.js 和 React.js 的朋友参考。&lt;/p&gt;
&lt;h4 id="Vue.js + V2EX 项目"&gt;Vue.js + V2EX 项目&lt;/h4&gt;
&lt;p&gt;代码地址：&lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/v2ex_frontend&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="http://v2ex.liuzhen.me" rel="nofollow" target="_blank"&gt;http://v2ex.liuzhen.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;关于这个项目的一些介绍和学习资料可以访问 &lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt; 查看 .&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/d0d8498d1f29b0504f80525c253558f4.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这篇文章主要介绍 React.js 的相关知识。&lt;/p&gt;
&lt;h4 id="React.js + RubyChina 项目"&gt;React.js + RubyChina 项目&lt;/h4&gt;
&lt;p&gt;代码地址：&lt;a href="https://github.com/liuzhenangel/react-ruby-china" rel="nofollow" target="_blank"&gt;https://github.com/liuzhenangel/react-ruby-china&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="http://ruby-china.liuzhen.me" rel="nofollow" target="_blank"&gt;http://ruby-china.liuzhen.me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/80a6fe01f6b95ba817df1c5d71e1ab0a.png!large" title="" alt=""&gt;&lt;/p&gt;
&lt;h5 id="项目介绍"&gt;项目介绍&lt;/h5&gt;
&lt;p&gt;react-ruby-china 项目是一个利用 react, react-dom, react-redux, react-router, redux, es6, redux-thunk 实现的 RubyChina 社区克隆项目。&lt;/p&gt;

&lt;p&gt;这是一个前后端分离项目，前端主要是 react, redux, es6, css 框架使用了 bootstrap. 后端利用 ruby-china 开放的 api. 支持响应式布局。部分功能仍在持续完善中。&lt;/p&gt;
&lt;h5 id="开发环境搭建"&gt;开发环境搭建&lt;/h5&gt;
&lt;p&gt;可以根据下方列出的官方文档里面有详细说明，这里介绍一下 &lt;code&gt;create-react-app&lt;/code&gt; 这个命令行脚手架工具。&lt;code&gt;npm install create-react-app -g&lt;/code&gt; 之后执行 &lt;code&gt;create-react-app my-app&lt;/code&gt;, 然后 &lt;code&gt;npm start&lt;/code&gt; 就能运行了.
关于 &lt;code&gt;create-react-app&lt;/code&gt; 详情可以点击 &lt;a href="https://github.com/facebookincubator/create-react-app" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt; 查看。&lt;/p&gt;
&lt;h5 id="核心技术框架"&gt;核心技术框架&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;react&lt;/li&gt;
&lt;li&gt;react-dom&lt;/li&gt;
&lt;li&gt;react-router&lt;/li&gt;
&lt;li&gt;redux&lt;/li&gt;
&lt;li&gt;redux-thunk&lt;/li&gt;
&lt;li&gt;react-md-editor&lt;/li&gt;
&lt;li&gt;isomorphic-fetch&lt;/li&gt;
&lt;li&gt;react-paginate&lt;/li&gt;
&lt;li&gt;react-redux&lt;/li&gt;
&lt;li&gt;marked&lt;/li&gt;
&lt;li&gt;es6-promise&lt;/li&gt;
&lt;li&gt;classnames&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="学习参考资料"&gt;学习参考资料&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;在学习 React 过程中，React.js 文档做的没有 Vue.js 的好，文档中的例子各种不同语法。对着照做不一定对，也不方便查询，踩过很多坑后给大家做个分享。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;React 中文文档 (这个文档很好查询，但是很多内容写的太简单了没讲清楚，而且内容不全): &lt;a href="https://hulufei.gitbooks.io/react-tutorial/content/index.html" rel="nofollow" target="_blank"&gt;https://hulufei.gitbooks.io/react-tutorial/content/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React 官方英文文档：&lt;a href="https://facebook.github.io/react/docs/getting-started.html" rel="nofollow" target="_blank"&gt;https://facebook.github.io/react/docs/getting-started.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React 中文文档 (这个文档比较差): &lt;a href="http://reactjs.cn/react/docs/getting-started-zh-CN.html" rel="nofollow" target="_blank"&gt;http://reactjs.cn/react/docs/getting-started-zh-CN.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;极客学院提供的 React 中文文档：&lt;a href="http://wiki.jikexueyuan.com/project/react/" rel="nofollow" target="_blank"&gt;http://wiki.jikexueyuan.com/project/react/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;另一个 Reac 中文文档 (这个比较全面，但是不便于搜索): &lt;a href="http://www.phperz.com/article/15/0712/140537.html" rel="nofollow" target="_blank"&gt;http://www.phperz.com/article/15/0712/140537.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React Router 中文文档：&lt;a href="https://react-guide.github.io/react-router-cn/" rel="nofollow" target="_blank"&gt;https://react-guide.github.io/react-router-cn/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RubyChina API: &lt;a href="https://ruby-china.org/api" rel="nofollow" target="_blank"&gt;https://ruby-china.org/api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ReacChina 社区 (这里面有很多资源): &lt;a href="http://react-china.org/" rel="nofollow" target="_blank"&gt;http://react-china.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ES6 文档：&lt;a href="http://es6.ruanyifeng.com/#docs/intro" rel="nofollow" target="_blank"&gt;http://es6.ruanyifeng.com/#docs/intro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Redux 介绍：&lt;a href="http://www.alloyteam.com/2015/09/react-redux/" rel="nofollow" target="_blank"&gt;http://www.alloyteam.com/2015/09/react-redux/&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Tue, 11 Oct 2016 17:54:19 +0800</pubDate>
      <link>https://ruby-china.org/topics/31287</link>
      <guid>https://ruby-china.org/topics/31287</guid>
    </item>
    <item>
      <title>用 Vue.js 实现了一个 V2EX 克隆项目</title>
      <description>&lt;p&gt;Rails 程序员一枚，最近在学习 Vue.js, 写了个项目，有兴趣的同学可以 start 一下.&lt;img title=":grinning:" alt="😀" src="https://twemoji.ruby-china.com/2/svg/1f600.svg" class="twemoji"&gt;&lt;/p&gt;
&lt;h2 id="Demo"&gt;Demo&lt;/h2&gt;
&lt;p&gt;项目 Demo 请访问：&lt;a href="http://v2ex.liuzhen.me/" rel="nofollow" target="_blank"&gt;http://v2ex.liuzhen.me/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;项目代码：&lt;a href="https://github.com/liuzhenangel/v2ex_frontend" rel="nofollow" target="_blank" title=""&gt;https://github.com/liuzhenangel/v2ex_frontend&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="项目介绍"&gt;项目介绍&lt;/h2&gt;
&lt;p&gt;v2ex_frontend 项目是一个利用 vue.js 和 v2ex api 实现的 V2EX 社区克隆项目，主要目的是为了学习 vue.js, 很适合学习 vue.js 的朋友参考。&lt;/p&gt;

&lt;p&gt;这是一个前后端分离项目，前端主要是 vue.js 和 vue-router, css 框架使用了 uikit. 后端利用 v2ex 开放的 api. 支持响应式布局。&lt;/p&gt;
&lt;h2 id="核心技术框架"&gt;核心技术框架&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;vue.js&lt;/li&gt;
&lt;li&gt;uikit&lt;/li&gt;
&lt;li&gt;lodash&lt;/li&gt;
&lt;li&gt;vue-paginate&lt;/li&gt;
&lt;li&gt;vue-router&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="系统依赖"&gt;系统依赖&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Node ( &amp;gt;= 6.5 )&lt;/li&gt;
&lt;li&gt;npm ( &amp;gt;= 3.10.6 )&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="学习参考资料"&gt;学习参考资料&lt;/h2&gt;
&lt;p&gt;vue.js 文档：&lt;a href="https://vuejs.org.cn/guide/overview.html" rel="nofollow" target="_blank"&gt;https://vuejs.org.cn/guide/overview.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vue-router 文档：&lt;a href="http://router.vuejs.org/zh-cn/index.html" rel="nofollow" target="_blank"&gt;http://router.vuejs.org/zh-cn/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;lodash 文档：&lt;a href="https://lodash.com/docs/4.15.0" rel="nofollow" target="_blank"&gt;https://lodash.com/docs/4.15.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;uikit 文档：&lt;a href="http://getuikit.com/index.html" rel="nofollow" target="_blank"&gt;http://getuikit.com/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;v2ex api: &lt;a href="https://gist.github.com/fanzeyi/6951803" rel="nofollow" target="_blank"&gt;https://gist.github.com/fanzeyi/6951803&lt;/a&gt;, &lt;a href="https://www.v2ex.com/p/7v9TEc53" rel="nofollow" target="_blank"&gt;https://www.v2ex.com/p/7v9TEc53&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Mon, 19 Sep 2016 13:54:06 +0800</pubDate>
      <link>https://ruby-china.org/topics/31090</link>
      <guid>https://ruby-china.org/topics/31090</guid>
    </item>
    <item>
      <title>[已解决] 根据 Sunspot 文档配置, 查询 boolean 字段时, 没有查询到任何匹配结果, google 无果, 求指教?</title>
      <description>&lt;p&gt;sunspot 文档：&lt;a href="https://github.com/sunspot/sunspot" rel="nofollow" target="_blank"&gt;https://github.com/sunspot/sunspot&lt;/a&gt;
配置：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;searchable&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:oneword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:description&lt;/span&gt;
   &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:category_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;multiple: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
   &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:city_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;multiple: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="ss"&gt;:published&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;数据库数据：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt; pry(main)&amp;gt; Project.all
  Project Load (2.5ms)  SELECT DISTINCT "projects".* FROM "projects"  WHERE "projects"."deleted_at" IS NULL
=&amp;gt; [#&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;id:&lt;/span&gt; &lt;span class="err"&gt;1,&lt;/span&gt; &lt;span class="na"&gt;name:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;baidu&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;oneword:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;Summary&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;description:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;adf&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;stage:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;industry:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;city:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;深圳&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;published:&lt;/span&gt; &lt;span class="na"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;created_at:&lt;/span&gt; &lt;span class="err"&gt;"2016&lt;/span&gt;&lt;span class="na"&gt;-02-29&lt;/span&gt; &lt;span class="err"&gt;03&lt;/span&gt;&lt;span class="na"&gt;:04:01&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;updated_at:&lt;/span&gt; &lt;span class="err"&gt;"2016&lt;/span&gt;&lt;span class="na"&gt;-02-29&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="na"&gt;:30:18&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;team_story:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;link:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;liuzhen.me&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;status:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;approved&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;deleted_at:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;,
 #&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;id:&lt;/span&gt; &lt;span class="err"&gt;2,&lt;/span&gt; &lt;span class="na"&gt;name:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;dd&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;oneword:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;dd&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;description:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;ddd&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;stage:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;industry:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;city:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;dd&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;published:&lt;/span&gt; &lt;span class="na"&gt;false&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;created_at:&lt;/span&gt; &lt;span class="err"&gt;"2016&lt;/span&gt;&lt;span class="na"&gt;-02-29&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="na"&gt;:44:23&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;updated_at:&lt;/span&gt; &lt;span class="err"&gt;"2016&lt;/span&gt;&lt;span class="na"&gt;-02-29&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="na"&gt;:44:23&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;team_story:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;link:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;liuzhen.me&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;status:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;drafted&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;deleted_at:&lt;/span&gt; &lt;span class="na"&gt;nil&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行查询：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt; Sunspot.search(Project) do
   with(:published, true)
end.results
D, [2016-02-29T21:03:46.567622 #9580] DEBUG -- :   SOLR Request (43.9ms)  [ path=select parameters={fq: ["type:Project", "published_b:true"], start: 0, rows: 30, q: "*:*"} ]
=&amp;gt; []
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>rina</author>
      <pubDate>Mon, 29 Feb 2016 21:11:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/29160</link>
      <guid>https://ruby-china.org/topics/29160</guid>
    </item>
    <item>
      <title>Discourse 单点登录</title>
      <description>&lt;p&gt;PS: 楼主是个新手，写错的地方还请指正 :)&lt;/p&gt;
&lt;h3 id="背景"&gt;背景&lt;/h3&gt;
&lt;p&gt;公司内部有个&lt;code&gt;discourse&lt;/code&gt;论谈：&lt;a href="http://stage.bbs.uboss.me/" rel="nofollow" target="_blank" title=""&gt;http://stage.bbs.uboss.me/&lt;/a&gt;,  想将这个论坛上注册功能屏蔽掉，注册登录功能统一到 Rails 项目：&lt;a href="http://stage.uboss.me/" rel="nofollow" target="_blank" title=""&gt;http://stage.uboss.me/&lt;/a&gt; 这个网站上登录，帐户也是&lt;a href="http://stage.uboss.me/" rel="nofollow" target="_blank" title=""&gt;http://stage.uboss.me/&lt;/a&gt;这个网站上的帐户信息。&lt;/p&gt;
&lt;h3 id="过程"&gt;过程&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;discourse&lt;/code&gt;本身#设置/登录#里有支持 sso 单点登录配置。具体文档信息可以看 &lt;a href="https://meta.discoursecn.org/t/Discourse-%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95%E5%8A%9F%E8%83%BD/52" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;. &lt;/p&gt;
&lt;h4 id="参数解析"&gt;参数解析&lt;/h4&gt;
&lt;p&gt;这里解释一下这几个配置字段的含义：&lt;/p&gt;

&lt;p&gt;sso_url: 这个参数的作用是当你点击 discourse 论坛的登录时，要跳转的路径，这里要求统一到&lt;a href="http://stage.uboss.me/" rel="nofollow" target="_blank" title=""&gt;http://stage.uboss.me/&lt;/a&gt;这里登录，所以地址自然指向这个路径，但是要指出具体指向哪个 action, 因为在这个 action 里要校验传入的 secret 和配置的 secret 是否一致。&lt;/p&gt;

&lt;p&gt;sso_secret : 这个 secret 是一个字符串，可以随意填写，但是必须和 action 里校验的一致。&lt;/p&gt;

&lt;p&gt;enable_sso : 开启 sso 登录模式。如果误启动了可能进行 discourse 项目，执行：&lt;code&gt;rails c&lt;/code&gt;后，设置：&lt;code&gt;SiteSetting.enable_sso = false&lt;/code&gt;就可以关闭了。&lt;/p&gt;
&lt;h4 id="添加一个Action"&gt;添加一个 Action&lt;/h4&gt;
&lt;p&gt;创建一个文件：&lt;code&gt;app/controllers/discourse_sso_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这里面要处理两件事：&lt;/p&gt;

&lt;p&gt;1. 判断用户是否登录，是：校验密码是否一致。&lt;/p&gt;

&lt;p&gt;2. 判断用户是否登录，否：跳转到登录页面&lt;/p&gt;

&lt;p&gt;参考代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DiscourseSsoController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sso&lt;/span&gt;  
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;
      &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SECRET'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;sso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SingleSignOn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;
      &lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;external_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'KEY'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# unique to your application&lt;/span&gt;
      &lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sso_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;sso&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'CALLBACK_URL'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_user_session_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;redirect: &lt;/span&gt;&lt;span class="s1"&gt;'discourse'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里如果用户没用登录，则跳转到登录页面。登录完成后需要跳转回 discourse 论坛 (此时论坛是登录状态), 所以在请求时将请求地址记录下来方便登录后跳转。&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;中添加&lt;/p&gt;

&lt;p&gt;内容如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:store_discourse_sso_location&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store_discourse_sso_location&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xhr?&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get?&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;discourse_sso_path&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:discourse_sso&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fullpath&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在&lt;code&gt;SessionsController&lt;/code&gt;判断一下，然后跳转到 session[:discourse_sso] 这个路径。&lt;/p&gt;

&lt;p&gt;这里面用到的几个参数解释一下：&lt;/p&gt;
&lt;h6 id="配置以下信息secret要与discourse上的secret一致, key 取一个唯一值, callback_url认证后跳转路径: http://discourse_url/session/sso_login\"&gt;配置以下信息&lt;code&gt;secret&lt;/code&gt;要与 discourse 上的 secret 一致，&lt;code&gt;key&lt;/code&gt; 取一个唯一值，&lt;code&gt;callback_url&lt;/code&gt;认证后跳转路径：&lt;a href="http://discourse_url/session/sso_login" rel="nofollow" target="_blank"&gt;http://discourse_url/session/sso_login&lt;/a&gt;\&lt;/h6&gt;
&lt;p&gt;SECRET: xxx
    KEY:123
    CALLBACK_URL: &lt;a href="http://stage.bbs.uboss.me/session/sso_login" rel="nofollow" target="_blank"&gt;http://stage.bbs.uboss.me/session/sso_login&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;考虑到密码的安全性，使用了 gem figaro, 配置使用文件可以 google 之。&lt;/p&gt;
&lt;h4 id="配置路由"&gt;配置路由&lt;/h4&gt;
&lt;p&gt;在 config/routes.rb 添加一条路由：&lt;code&gt;get '/discourse/sso', to: 'discourse_sso#sso'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这个 url 配置是在 discourse 上配置 sso_url 用到的。&lt;/p&gt;
&lt;h3 id="添加discourse中的single_sign_on文件"&gt;添加 discourse 中的 single_sign_on 文件&lt;/h3&gt;
&lt;p&gt;放于 &lt;a href="https://github.com/discourse/discourse/blob/master/lib/single_sign_on.rb" rel="nofollow" target="_blank" title=""&gt;lib/single_sign_on.rb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;做好了这些之后就可以开始测试了。&lt;/p&gt;

&lt;p&gt;此文来自 &lt;a href="http://liuzhen.me/articles/18" rel="nofollow" target="_blank" title=""&gt;Rina's Blog&lt;/a&gt;&lt;/p&gt;</description>
      <author>rina</author>
      <pubDate>Wed, 28 Oct 2015 17:58:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/27873</link>
      <guid>https://ruby-china.org/topics/27873</guid>
    </item>
  </channel>
</rss>
