Rails 入門最佳實(shí)踐

花了兩個(gè)月做了一個(gè)類似 Tower 的GTD工具, 從最開始學(xué)習(xí) Ruby 和 Rails, 到跌跌撞撞中摸索 Rails 的各種小技巧, 直到最后一塊拼圖的完成, 才感覺自己掌握了 Rails 構(gòu)建Web產(chǎn)品方法和技巧.

Tower NG

在自學(xué) Rails 的這幾個(gè)月, 也看了很多現(xiàn)成的文章, 雖然很多文章都寫的非常詳細(xì), 但是對(duì)于初學(xué)者來說, 沒有重點(diǎn)的詳細(xì)只會(huì)給人一種盲人摸象的感覺, 感覺很強(qiáng)大, 心里卻沒有底.

所以, 我一直在想寫一篇重新梳理過的 Rails 教程, 能夠幫助后來的 Rails 自學(xué)者更快的掌握整個(gè) Rails 的脈絡(luò)得以快速上手, 也就是今天的 << Rails入門最佳實(shí)踐 >>

預(yù)備知識(shí)

因?yàn)橛?Rails 開發(fā)Web項(xiàng)目, 首先需要懂 Ruby 編程和基本的 Rails 操作, 所以建議你先把下面這兩本書看完以后再來反過來閱讀本文, 會(huì)有茅塞頓開的感覺, 哈哈哈哈.

  1. Ruby: Ruby Essentials
  2. Rails: Ruby on Rails 指南

極簡(jiǎn)理念

就像我剛開始看了上面的兩本書以后, 我依然沒法脫離 "Ruby on Rails指南" 本書來獨(dú)立構(gòu)建項(xiàng)目, 因?yàn)?Web 的知識(shí)太碎了, 你只有把每個(gè)模塊都弄懂并串聯(lián)起來, 你才能知道怎么做, 而看了指南這本書以后, 雖然對(duì)怎么構(gòu)建 Web 項(xiàng)目有一個(gè)簡(jiǎn)單的認(rèn)識(shí), 但是怎么自己構(gòu)建和擴(kuò)展功能, 還是一頭霧水.

所以, 本文是在你看了上面兩本書以后, 針對(duì)這兩本書遺漏和馬上有疑問的點(diǎn), 用極簡(jiǎn)通俗的語言來補(bǔ)齊知識(shí)體系缺失的一環(huán), 希望用最少篇幅讓你知道怎么把所學(xué)的知識(shí)串聯(lián)起來.

極簡(jiǎn)理念分為心法和劍法兩部分, 心法就是告訴你理論應(yīng)該怎么做(讓你先有眼高手低的感覺, 哈哈哈), 劍法就是實(shí)地一步一步的實(shí)踐來疏通你的任督二脈.

心法

學(xué)習(xí) Rails 最重要的是, 需要清楚的知道消息響應(yīng)的循環(huán), 只有知道消息從哪里發(fā)出, 哪里經(jīng)過, 最后以怎樣的形式返回, 才能在問題發(fā)生時(shí)知道怎么準(zhǔn)確的定位問題.

注意看下面這張圖:


消息響應(yīng)循環(huán)
  1. 首先你的瀏覽器訪問網(wǎng)頁的時(shí)候, 比如本地的 0.0.0.0, 瀏覽器會(huì)向 Rails 后臺(tái)發(fā)送 0.0.0.0 的 GET 請(qǐng)求
  2. 路由器 (Router) 會(huì)直接返回路由中 root 路徑對(duì)應(yīng)的頁面, 這就是我們?cè)L問網(wǎng)站的首頁
  3. 在首頁中點(diǎn)擊 <a> 標(biāo)簽的連接, 瀏覽器從 <a> 標(biāo)簽中提取 href 路徑繼續(xù)向 Rails 發(fā)送 HTTP 請(qǐng)求
  4. 路由器根據(jù) href 請(qǐng)求的路徑和路由表, 找到相同名字的控制器(Controller), 并調(diào)用控制器中對(duì)應(yīng)的動(dòng)作 (index, show, edit, update, destroy) 函數(shù)去執(zhí)行
  5. 控制器動(dòng)作函數(shù)一般會(huì)查詢模型(Model)的數(shù)據(jù), 根據(jù)動(dòng)作函數(shù)中的邏輯來產(chǎn)生不同的請(qǐng)求響應(yīng) (JSON, JS 或者 html.erb 模板文件)
  6. 瀏覽器根據(jù)控制器返回的請(qǐng)求響應(yīng)來更改當(dāng)前的頁面, 以完成一次完整的消息循環(huán)處理

Rails 在控制器 respond_to 處理響應(yīng)的時(shí)候有四種方式:

  1. 第一種是直接返回 html.erb 文件, html.erb 文件會(huì)根據(jù)填充數(shù)據(jù)生成新的 html 文件替換現(xiàn)有的頁面
  2. 返回 js.erb 文件, 根據(jù)填充數(shù)據(jù)生成新的 js 文件直接在當(dāng)前頁面中執(zhí)行代碼操作 DOM 元素
  3. 返回 json 數(shù)據(jù)給 ajax , 由瀏覽器中 ajax的js回調(diào)來處理返回的 json 數(shù)據(jù), 并操作當(dāng)前頁面的 DOM 元素
  4. 當(dāng)然也可以直接用 redirect_to new_path 跳轉(zhuǎn)到 new_path 頁面

只要把這個(gè)消息響應(yīng)循環(huán)銘記于心, 你已經(jīng)就理解了 Rails 一半了, 雖然 Rails 功能強(qiáng)大, 但是本質(zhì)上 Rails 就是按照上面的消息循環(huán)來處理所有的 HTTP 請(qǐng)求.

劍法

劍法部分主要是實(shí)操, 主要分為四個(gè)部分:

  1. 三板斧, 三板斧學(xué)會(huì)了Web項(xiàng)目馬上就可以上手
  2. 錦囊妙計(jì), 提供各種小技巧來靈活解決一些現(xiàn)實(shí)中的障礙
  3. 目錄參考, 講解一下Web開發(fā)最主要需要了解的一些目錄
  4. 擴(kuò)展閱讀, 通過系統(tǒng)學(xué)習(xí)某一本書來夯實(shí)知識(shí)體系
第一板斧: 從 Restful 的角度打通路由丘喻、控制器、視圖

看了很多關(guān)于 Rails 的文章, 上來就說, 你要做這個(gè)命令, 那個(gè)命令, 然后你就可以訪問到頁面了.

其實(shí)我們?cè)倩叵胍幌?"消息響應(yīng)循環(huán)" 那張圖, Web本質(zhì)是什么?

Web的本質(zhì)就是用戶點(diǎn)擊HTML的連接, 更新當(dāng)前頁面.
更新的方式可以是直接跳轉(zhuǎn), 或者用新的頁面替換, 或者JS直接操作DOM元素

在本質(zhì)之上, 才是各種工具, 插件,性能優(yōu)化和架構(gòu)設(shè)計(jì)等.

然而 Rails 的本質(zhì)是什么呢?

Rails 的本質(zhì)就是根據(jù) Restful 的設(shè)計(jì)原則來修改路由, 控制器和模板等文件
使得 Rails 能夠按照 "消息響應(yīng)循環(huán)" 一直循環(huán)下去

所以, Rails 的大部分工作, 就是下面這幾件事情:

  1. 改路由 (routes.rb), 讓Rails可以根據(jù)發(fā)送過來的 href 連接和路由設(shè)置去找到控制器和對(duì)應(yīng)的動(dòng)作函數(shù)
  2. 創(chuàng)建對(duì)應(yīng)的控制器 (resources_controller.rb) 并添加動(dòng)作函數(shù) (action)
  3. 在動(dòng)作函數(shù)中, 從模型 (resources.rb) 中抓取數(shù)據(jù), 根據(jù) respond_to 表達(dá)式來返回響應(yīng)結(jié)果 (html.erb, js.erb, json, redirect_to)
  4. 修改 js 代碼來處理 DOM 元素

Rails 的所有開發(fā)都是圍繞著上面這四點(diǎn)來展開的.

說到啥是 Restful API ? 不用想什么高大上的概念, 其實(shí)就是結(jié)合訪問資源的路徑 + HTTP的請(qǐng)求類型來自動(dòng)對(duì)應(yīng) controller.rb 里面不同動(dòng)作函數(shù) (index, new, edit, show, update, destroy) 的規(guī)范和技術(shù).

不同的動(dòng)作函數(shù)在所有資源中對(duì)應(yīng)的意義是一致的:

  1. index 就是顯示資源的列表
  2. show 就是顯示某一個(gè)資源
  3. new 就是創(chuàng)建資源
  4. edit 就是編輯資源
  5. update 就是更新資源
  6. destroy 就是刪除資源

我們以任務(wù)的圖來形象的給出不同動(dòng)作最終應(yīng)該生成的頁面長(zhǎng)什么樣子?


mission index
mission show
mission new
mission edit
mission update
mission destroy

所以, 如果我們要建立一批像上面 "任務(wù)" 的頁面, 我們應(yīng)該怎么做?

  1. 修改 config/routes.rb 增加 missions 這個(gè)資源:
Rails.application.routes.draw do
  resources :missions
end
  1. 創(chuàng)建 app/controllers/missions_controller.rb 這個(gè)文件, 并創(chuàng)建動(dòng)作函數(shù):
class MissionsController < ApplicationController
  def index
  end

  def show
  end

  def new
  end

  def edit
  end

  def update
  end

  def destroy
  end
end
  1. 如果默認(rèn)只是返回動(dòng)作對(duì)應(yīng)的模板頁面, 上面的函數(shù)不用加什么內(nèi)容, 直接在 app/views/missions 目錄中分別創(chuàng)建 index.html.erb , show.html.erb, new.html.erb, edit.html.erb, update.html.erb, destroy.html.erb 的模板文件即可.

上面就是Rails創(chuàng)建頁面的核心步驟, 只要你完成上面的步驟后, 在頁面中加入 <a> 標(biāo)簽連接后, Rails 會(huì)按照下面的對(duì)照方式自動(dòng)渲染頁面的:

Rails Path Url Path Http Type Controller action
missions_path /missions GET index
missions_path /missions POST create
new_team_mission_path /missions/new POST new
edit_mission_path /missions/id/edit GET edit
missions_path /missions/id GET show
missions_path /missions/id PATCH update
missions_path /missions/id DELETE destroy

請(qǐng)仔細(xì)看上面的圖, 在 Rails 中, 不同的 PATH 和 不同的 HTTP 請(qǐng)求類型對(duì)應(yīng)就會(huì)自動(dòng)讓 Rails 去控制器中找對(duì)應(yīng)的 action, 然后根據(jù) action 的名字生成對(duì)應(yīng)的 html 模板文件.

所以, 最后總結(jié)來說, 在 Rails 里你需要添加一個(gè)新的資源來處理頁面, 假設(shè)這個(gè)資源叫 foo, 你需要做的就是再重復(fù)上面的步驟:

  1. rails g model foo 生成一個(gè)數(shù)據(jù)庫表
  2. routes.rb 加上 resources foo
  3. 創(chuàng)建 foos_controller.rb 文件
  4. 在目錄下 view/foos/ 創(chuàng)建動(dòng)作對(duì)應(yīng)的 *.html.erb 文件
第二版斧: 獨(dú)善其身的模型

當(dāng)你執(zhí)行命令 rails g model foo attr_a:integer attr_b:integer 生成模型的時(shí)候, 也就創(chuàng)建了
app/models/foo.rb 文件:

class Foo < ApplicationRecord
end

在模型文件中, 我們是可以直接訪問數(shù)據(jù)表的屬性的, 比如下面這樣:

class Foo < ApplicationRecord
   def print_attr
      printf("%<attr_a>s %<attr_b>s", attr_a: attr_a, attr_b: attr_b)
   end
end

第二扳斧比較簡(jiǎn)單, 就是模型文件中只放一些跟數(shù)據(jù)表屬性相關(guān)的工具函數(shù)就可以了, 跟產(chǎn)品業(yè)務(wù)相關(guān)的代碼全部都放到控制器 foos_controller.rb 中.

上面的 print_attr 是 Foo 的實(shí)例函數(shù), 如果需要?jiǎng)?chuàng)建 Foo 的類函數(shù)需要使用下面的方式:

class Foo < ApplicationRecord
   class << self
     def class_func
        printf("I'm a class function")
     end
   end
end

然后就可以直接使用 Foo.class_func 來調(diào)用了.

還有一些非常獨(dú)特的情況, 就是針對(duì)模型函數(shù)會(huì)在多個(gè)控制器中使用, 甚至是多個(gè) *.html.erb 模板文件中調(diào)用, 這時(shí)候就可以用 helper 模塊來處理.

比如我們創(chuàng)建一個(gè)跟 session 相關(guān)的 helper 模塊 app/helpers/sessions_helper.rb

module SessionsHelper
  def log_in(user)
    session[:user_id] = user.id
  end
end

然后在 app/controllers/application_controller.rb 文件中加入 include 語句:

class ApplicationController < ActionController::Base
  include SessionsHelper
end

這樣, 我們就可以在所有的模式、控制器祥款、視圖文件中訪問 log_in 函數(shù)了.

第三板斧

前兩板斧主要講了怎么生成資源頁面和模型文件中功能函數(shù)的處理, 現(xiàn)實(shí)的Web場(chǎng)景不僅僅是跳轉(zhuǎn)到新的頁面或者大范圍更新當(dāng)前頁面的內(nèi)容, 更多的場(chǎng)景是, 根據(jù)用戶的交互行為, 局部微小的改變一小塊界面來進(jìn)行視覺反饋.

第三板斧講的主要就是怎么在 Rails 中使用 JavaScript, JavaScript的代碼編寫的時(shí)候, 時(shí)刻問自己, 從哪里發(fā)起 submit 或者 ajax ? 發(fā)送完成后是否要處理返回?cái)?shù)據(jù)?

JavaScript 主要有四種情況:

1. 表單的類型, 只提交, 不處理返回?cái)?shù)據(jù)
<%= form_for(:session, url: sign_in_path) do |f| %>
    <%= f.email_field :email, class: "form-control", placeholder: "登錄郵箱" %>
    <%= f.password_field :password, class: "form-control", placeholder: "密碼" %>

    <%= f.submit "登錄", class: "btn btn-primary" %>
<% end%>

比如這種最簡(jiǎn)單的, 在 form_for 里面直接點(diǎn)擊按鈕, 就執(zhí)行 submit 動(dòng)作, 這種情況, 我們只需要控制 form_for 里的 url 字段, 也就是前面說的資源路徑, form_for 會(huì)自動(dòng)用 POST 請(qǐng)求調(diào)用資源的 create 動(dòng)作函數(shù)的.

2. ajax 發(fā)送異步請(qǐng)求, 并處理返回的模板數(shù)據(jù):
$.ajax({type: "POST",
        url: "/missions/1",
        success: function(result) {
        }
    })

def edit
  respond_to do |format|
    format.html do
      render "_foo",
             layout: false
    end
  end
end

上面這段代碼就是最簡(jiǎn)單的模板返回樣例, format.html 的意思就是返回一個(gè)模板, render 的意思就是直接渲染模板 app/views/layouts/_foo.html.erb 的內(nèi)容

layout: false 這句強(qiáng)調(diào)的是不要在 _foo.html.erb 外包裹其他模板, 文件 _foo.html.erb 顯示的是啥內(nèi)容就用啥內(nèi)容, 因?yàn)楹芏鄷r(shí)候 _foo.html.erb 模板在作為 ajax 的返回的數(shù)據(jù)并代表一個(gè)完整的頁面, 而僅僅只是一個(gè) div 的模板內(nèi)容用于替換局部的DOM元素.

3. ajax 發(fā)送異步請(qǐng)求, 并處理返回的 json 數(shù)據(jù)
$.ajax({type: "POST",
        url: "/missions/1",
        success: function(result) {
           console.log(result["status"])
        }
    })

def edit
 respond_to do |format|
      format.json do
        render json: { status: "destroy" }
      end
  end
end

和返回模板數(shù)據(jù)的格式類似, 唯一的不同是 format.html 變成了 format.json, 然后通過 json: { key: "value" } 的形式返回JSON數(shù)據(jù)給 ajax 請(qǐng)求.

4. 第三方插件發(fā)送表單請(qǐng)求, 在 ajax 成功后執(zhí)行JS代碼
上傳頭像

我們來舉一個(gè)簡(jiǎn)單的例子, 如果我們要實(shí)現(xiàn)上圖中這種上傳頭像后自動(dòng)更新頁面中兩處頭像元素的功能, 我們一般會(huì)按照下圖這種流程來處理:


image.png
  1. 首先我們會(huì)在 form_with 表單中增加 data-controller 和 data-action 字段, 表示 AJAX 成功返回結(jié)果后, 調(diào)用 app/javascript/controllers/user_controller.js的 update 函數(shù), submit 按鈕點(diǎn)擊后提交數(shù)據(jù)給 user_controller.rb 中的 update 函數(shù)
  2. user_controller.rb 控制器在處理數(shù)據(jù)后, 返回的并不是 JS 文件, 而是返回 JSON 數(shù)據(jù)
  3. Stimulus 的JS文件在接到 AJAX 返回的 JSON 數(shù)據(jù)后在瀏覽器端修改 HTML頁面的DOM結(jié)構(gòu)

下面就是抽象的消息響應(yīng)循環(huán):


ajax:sucess 消息響應(yīng)循環(huán)

因?yàn)橄襁@種第三方插件, 有時(shí)候我們往往并不能用 ajax 簡(jiǎn)單的替換 submit 的操作, 所以這種情況, 我們依然會(huì)采用 form_with 的方式提交表單, 但是會(huì)在 ajax:success 的方式使得請(qǐng)求返回 JSON 數(shù)據(jù)的時(shí)候調(diào)用我們制定的 JS 函數(shù).

這其中的關(guān)鍵就是

data-action: "ajax:success->user#update"

這一句, 這一句起到了承上啟下的作用, 這種方法相對(duì)于 Rails 傳統(tǒng)的 SJR 方法的優(yōu)勢(shì)可以參考我的另一篇文章 SJR 結(jié)合 Stimulus 構(gòu)建可維護(hù)的JavaScript代碼

第四種情況比較復(fù)雜, 沒有前面三種那么簡(jiǎn)單易懂, 還需要對(duì) StimulusJS 和傳統(tǒng)的 SJR 方式比較了解, 建議看最后推薦的 StimulusJS Handbook 進(jìn)一步學(xué)習(xí).

錦囊秘籍

到目前為止, 如果你掌握了我上面說的三板斧的內(nèi)容, 其實(shí)你已經(jīng)可以流暢的使用 Rails 來開發(fā) Web 項(xiàng)目了.

下面將會(huì)針對(duì)一些 Rails 的小技巧逐一分享, 以幫助才學(xué)習(xí)完 "Rails on Ruby指南" 后的很多困惑

嵌套路由和HashID

我們經(jīng)常會(huì)看到很多Web項(xiàng)目的連接都長(zhǎng)這樣:
http://0.0.0.0:3000/projects/9KRL0W296QZXO4RP1HD37JGDPNVE1MY8/missions/KVM8OGX0NWK69L9ERHWLD2P4RYE1J3Q5

這種嵌套路由的好處就是, 可以讓開發(fā)團(tuán)隊(duì)有一個(gè)明顯的從屬關(guān)系, 讓產(chǎn)品更有邏輯性, 其實(shí)在 Rails 中做嵌套路由是非常簡(jiǎn)單的, 只用在 routes.rb 中寫下下面的內(nèi)容即可:

Rails.application.routes.draw do
  resources :projects do
    resources :missions
  end
end

Rails會(huì)在你訪問 mission 資源的時(shí)候, 自動(dòng)在 mission 資源前面加入 project 的前綴.

你會(huì)發(fā)現(xiàn), 上面的 projects 和 missions 后面的 ID 感覺都是 hash 過的, 這種處理一般是防止通過資源的數(shù)字id猜出產(chǎn)品的規(guī)模.

HashID 的處理很簡(jiǎn)單, 只用在 Gemfile 加入

gem "hashid-rails"

以后, 在需要處理的資源文件中加入 include Hashid:Rails 的語句

class Mission < ApplicationRecord
  include Hashid::Rails
end

這樣訪問路徑的時(shí)候就自動(dòng) Hash 資源的數(shù)字 id

通過 HashID 可以反向獲取對(duì)象, 就像這樣:

mission = Mission.find_by_hashid("hashid_string")
子模板的嵌入和參數(shù)判斷

為了避免重復(fù)代碼, 我們有時(shí)候會(huì)在模板中再嵌入之模板, 一般都使用下面類似的代碼:

  <%= render "layouts/foo" %>

如果子模板 app/views/layouts/_foo.html.erb 中可以傳入 keyword 的參數(shù), 但是上面的代碼調(diào)用子模板時(shí)卻什么參數(shù)都沒有調(diào)用, 可以在子模板中使用 local_assigns.has_key? 的方式來判斷參數(shù)是否傳入:

<% if local_assigns.has_key? :keyword %>
     ...
<% else %>
     ...
<% end %> >
手機(jī)頁面的處理

因?yàn)?Turbolinks 的加速處理, Rails 渲染手機(jī)頁面也是非常快速的, 但是怎么針對(duì)手機(jī)的尺寸單獨(dú)進(jìn)行手機(jī)頁面適配呢?

首先需要在 Gemfile 加入瀏覽器設(shè)備探測(cè)的插件:

gem "browser"

再在 app/controllers/application_controller.rb 文件中加入:

class ApplicationController < ActionController::Base
  before_action :detect_browse_device

  private

  def detect_browse_device
    request.variant = :phone if browser.device.mobile?
  end
end

最后在 views/foos/ 目錄下, 新建一個(gè) new.html+phone.erb 的模板就行了, Rails 如果發(fā)現(xiàn)手機(jī)訪問時(shí)會(huì)優(yōu)先調(diào)用 *html+phone.erb" 的模板文件.

我們只需要很少的幾個(gè) rails 腳手架命令

如果你看完 "Ruby on Rails 指南" 就會(huì)發(fā)現(xiàn), 按照我上面的文章, 新建控制器涵叮、視圖等文件都不需要 rails 的腳手架命令, 手動(dòng)創(chuàng)建文件的方式更簡(jiǎn)單也讓我們更加深刻的理解了 Rails 的消息響應(yīng)流程, 所以我強(qiáng)烈建議除了創(chuàng)建數(shù)據(jù)表的時(shí)候我們使用 rails 腳手架命令, 其他的都全部用手工創(chuàng)建文件的方式來執(zhí)行.

我平常需要使用 rails 腳手架的命令只有下面這幾個(gè):

  1. rails s: 啟動(dòng)服務(wù)器
  2. rails c: 啟動(dòng)調(diào)試終端
  3. rails g model Activity mission_id:integer content:string : 創(chuàng)建一個(gè)兩列的 Activity 模型
  4. rails g migration add_user_id_to_activity user_id:integer : 給現(xiàn)有的模型增加一列
  5. rails g migration rename_activity_type_column : 重命名一列
  6. rails g migration RemoveAvatarThumbFromUsers avatar_thumb:string : 從現(xiàn)有模型刪除一列
  7. rake db:migrate : 合并數(shù)據(jù)表變動(dòng)
  8. rake db:purge : 清空數(shù)據(jù)庫內(nèi)容

常用的Rails目錄簡(jiǎn)介

Rails 是一個(gè)約定即為規(guī)則的框架, 文件放錯(cuò)了就沒效果了, 下面是一些常用目錄的位置及作用說明

文件路徑 說明
Gemfile 包管理文件
config/routes.rb 路由配置文件
app/controllers 控制器目錄
app/models 模型目錄
app/views 視圖目錄
app/helpers helper模塊目錄
app/javascript/controllers StimulusJS控制器目錄
app/assets/stylesheets/custom 自定義CSS文件
db/migrate 數(shù)據(jù)庫合并記錄目錄

擴(kuò)展閱讀

上面的內(nèi)容主要是針對(duì)初學(xué) Rails 并期望快速實(shí)戰(zhàn)上手的同學(xué), 但是開發(fā)一個(gè)完整的Web產(chǎn)品還需要學(xué)習(xí) CSS铅辞、JQuery以及Rails才推出的 StimulusJS, 這些都需要系統(tǒng)性的學(xué)習(xí)才能融匯貫通.

  • CSS揭秘 CSS高級(jí)編程技巧書籍, 特別是偽元素和各種奇淫技巧, 可以非常優(yōu)雅的實(shí)現(xiàn)復(fù)雜的界面效果
  • 鋒利的 JQuery 系統(tǒng)的學(xué)習(xí)JQuery 的好書
  • StimulusJS Handbook StimulusJS 能夠非常清晰的、模塊化的開發(fā)JS功能, 同時(shí)保持JS代碼的可維護(hù)性
  • BootStrap 對(duì)多平臺(tái)自適應(yīng)做的很好, 內(nèi)置很多方便的小控件, 不用自己造. ;)

上面是一些擴(kuò)展閱讀和連接, 希望今天的文章能夠幫助更多人的人更快入門 Rails 全棧開發(fā).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末槽地,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捌蚊,老刑警劉巖集畅,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異缅糟,居然都是意外死亡挺智,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門窗宦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赦颇,“玉大人,你說我怎么就攤上這事赴涵∶角樱” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵髓窜,是天一觀的道長(zhǎng)扇苞。 經(jīng)常有香客問我,道長(zhǎng)寄纵,這世上最難降的妖魔是什么鳖敷? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮程拭,結(jié)果婚禮上定踱,老公的妹妹穿的比我還像新娘。我一直安慰自己恃鞋,他們只是感情好屋吨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著山宾,像睡著了一般至扰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上资锰,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天敢课,我揣著相機(jī)與錄音,去河邊找鬼绷杜。 笑死直秆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鞭盟。 我是一名探鬼主播圾结,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼齿诉!你這毒婦竟也來了筝野?” 一聲冷哼從身側(cè)響起晌姚,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎歇竟,沒想到半個(gè)月后挥唠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡焕议,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年宝磨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盅安。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唤锉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出别瞭,到底是詐尸還是另有隱情腌紧,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布畜隶,位于F島的核電站,受9級(jí)特大地震影響号胚,放射性物質(zhì)發(fā)生泄漏籽慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一猫胁、第九天 我趴在偏房一處隱蔽的房頂上張望箱亿。 院中可真熱鬧,春花似錦弃秆、人聲如沸届惋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脑豹。三九已至,卻和暖如春衡查,著一層夾襖步出監(jiān)牢的瞬間瘩欺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來泰國打工拌牲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留俱饿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓塌忽,卻偏偏與公主長(zhǎng)得像拍埠,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子土居,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 2018web前端最新面試題總結(jié) 一枣购、Html/Css基礎(chǔ)模塊 基礎(chǔ)部分 什么是HTML嬉探?答:? HTML并不是...
    duans_閱讀 4,667評(píng)論 3 27
  • React.js的Rails開發(fā)者指南 原作者:Fernando Villalobos 原文鏈接:https://...
    不知道為啥被屏蔽閱讀 3,699評(píng)論 0 24
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)坷虑,斷路器甲馋,智...
    卡卡羅2017閱讀 134,658評(píng)論 18 139
  • 夢(mèng)想著開個(gè)屬于自己的咖啡廳,就像《第36個(gè)故事》里面朵兒開的那樣:各種好看又美味的咖啡和甜點(diǎn)迄损,可以把整個(gè)人陷進(jìn)去的...
    肖倩雯閱讀 346評(píng)論 0 0
  • 前言:最近做項(xiàng)目上傳文件到騰訊云定躏,在自己手上的真機(jī)上測(cè)試沒有出現(xiàn)任何問題,提交測(cè)試后芹敌,也沒出現(xiàn)任何問題痊远,都可以上傳...
    跑調(diào)的安眠曲閱讀 3,244評(píng)論 4 3