本來想做 buddha(菩薩)論壇的,發現自己參考的項目太難實現,猝
筆者回爐重修了一番,正好發現了 realworld,遂決定將 realworld 項目代替原先的 buddha 項目,還是要量力而行,不要一意孤行(項目規劃太大,浪費太多時間學習)
先介紹一下 realworld 項目
源碼:https://github.com/gothinkster/realworld
demo:https://demo.realworld.io/#/
UI:https://github.com/gothinkster/conduit-bootstrap-template
頁面分析:https://www.jianshu.com/p/6014a9fefabd
從頁面角度講,只有七個頁面,即
- 首頁(index)
- 文章詳情頁(article)
- 登錄頁(login)
- 註冊頁(register)
- 寫文章頁(editor)
- 設置頁(settings)
- 個人頁(profile)
接口方面和數據結構直接看 文檔 就好,不説虛的,這個項目有19個接口,19個接口放其他語言要做多久?不知道,但 Ruby 應該花不了多少時間
介於此項目是個全棧項目,遂會前後端穿插地寫,項目名我起好了:地宮(Underground Palace)
文章目錄
搭建項目並部署
使用腳手架創建 article
穿上 bootstrap
新增fontawesome
device 用户體系
devise-i18n國際化
設置頁
個人頁
模型建立
查詢功能
訂閲功能
分頁功能
再次部署
logo設計
後記
搭建項目並部署
我們先新建項目
rails new underground-palace
cd list
然後去 config/routes.rb 中修改根目錄:
Rails.application.routes.draw do
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
root "rails/welcome#index"
end
我們通過 fly.io 來部署我們的服務,對其不過多介紹,具體可看上篇文章——前端學Ruby:唐詩項目部署優化
fly launch # 創建
fly deploy # 部署
fly open # 打開剛剛部署的項目
此時訪問 https://underground-palace.fly.dev/ (這裏我們的 underground 少寫了一個字母,無傷大雅,後續已修正)就能看到剛還在本地新建的項目,是不是很快,有點意想不到的感覺
使用腳手架創建 article
rails 的一個特點是一個命令就做很多事情,例如接下來我們要用 rails generate scaffold 完成 article 的增刪改查
rails g scaffold article title:string description:string body:text
rails db:migrate # 數據遷入
並且修改config/routes.rb :
Rails.application.routes.draw do
resources :articles
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
root "articles#index"
# root "rails/welcome#index"
end
如此,用腳手架搭建的文章的增刪改查就完成了,是不是很快
穿上 bootstrap
realworld 項目是基於 bootstrap 的,我們需要下載 bootstrap 的 gem
這裏需要做一下説明,像 bootstrap-sass gem 是基於 bootstrap 3 的樣式,bootstrap gem 是最新版的 boostrap,也可以理解為 bootstrap 3 及一下可使用 bootstrap-sass,反之則用 boostrap
因為 realworld 是基於 bootstrap4.0.0,所以下載時我們需要先設定好版本。按照 readme 的步驟,在 gemfile 文件中引入 boostrap 和 jquery-rails 包,再新增 common/footer 和 common/header 頁面,將模板代碼放進去
但是 readlworld 所提供的 bootstrap 和 線上版本 有差異,並不是直接引用能用(後續看到文檔中有現成的 模板,但不知道有沒有坑)
既然選擇了做用 bootstrap 來做UI,索性用最新的 bootstrap5
我們不按照 gem 方式引入 bootstrap,用 cssbundling-rails、 jsbundling-rails 來構建資源
bundle add cssbundling-rails jsbundling-rails
查找我們與 css 相關的構建命令
rails | grep css
同理查看我們與 javascript 構建相關的命令
rails | grep javascript
我們下載 bootstrap,基於 yarn
rails css:install:bootstrap
下載 esbuild,也是基於yarn下載,
rails javascript:install:esbuild
但是報錯 Could not resolve "app/javascript/*.*"
不用慌,去package.json 修改 build 中的配置,將esbuild app/javascript/*.* --bundle --sourcemap... 改成 esbuild app/javascript/application.js --bundle --sourcemap...
並執行 npm run build 執行代碼,當然,有些文件需要隱藏的這裏不做過多描述
當能 build 成功後,我們開發就是用bin/dev 命令來開發
但因為筆者使用的是 window 系統,所以會因此報錯:
unset 不是 window 的命令,所以我們要改造,前往根目錄下的 Procfile.dev 修改:
web: set "PORT=" && rails s
css: yarn build:css --watch
js: yarn build --watch
此時執行 /bin/dev 就能啓動我們的項目了,其以上代碼是啓動 rails 服務,css 和 js 都是通過 yarn build 打包後監聽(watch)變化,所以能做到熱更新
新增fontawesome
按照好 bootstrap 後還不夠,還需要安裝圖標,例如我們常用的fontawesome
首先安裝 Font Awesome:
yarn add @fortawesome/fontawesome-free
然後在 config/initializers/assets.rb 添加以下內容:
Rails.application.config.assets.paths << Rails.root.join('node_modules/@fortawesome/fontawesome-free/webfonts')
最後在 app/assets/stylesheets/application.sass.scss 添加以下內容:
$fa-font-path: ".";
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "@fortawesome/fontawesome-free/scss/solid.scss";
接着就是把具體的 articles、articles#show、articles#new頁面的模板樣式補充好
用户體系
我們使用 devise 來做我們的登錄註冊
安裝 devise gem 包
bundle add devise
運行以下命令生成 Devise 文件
rails g devise:install
創建一個用户模型(例如User),並運行以下命令生成 Devise 所需要的視圖和控制器:
rails g devise user
運行數據庫遷移以創建 Devise 所需要的表
rails db:migrate
如此這般,登錄註冊忘記密碼等一系列 CRUD 就做好了,我們只需要在 header.html.erb 中修改配置,將未登錄時顯示登錄註冊樣式即可,即
...
<% if !current_user %>
<!-- 未登錄 -->
<div class="col-md-3 text-end">
<%= link_to '註冊', new_user_registration_path, class: 'btn btn-outline-primary me-2' %>
<%= link_to '登入', new_user_session_path, class: 'btn btn-primary' %>
</div>
<% else %>
<!-- 登錄 -->
<% end %>
...
默認情況下,我們是看不到 devise 的視圖和控制器的,因為我們要修改 UI,所以將視圖釋放出來:
rails g devise:views
前往視圖層,修改views/devise/registrations/new.html.erb (註冊頁)和views/devise/session/new.html.erb(登錄頁)的樣式
默認情況下,註冊、登錄的路由是users/sign_up 和users/sign_in,和傳統意義上的註冊、登錄路由不符,這裏做一下映射,前往config/routes.rb中修改:
Rails.application.routes.draw do
- devise_scope :user
+ devise_scope :user do
+ get '/login' => 'devise/sessions#new'
+ get '/register' => 'devise/registrations#new'
+ end
...
end
並前往views/common/_header.html.erb 中修改代碼:
<!-- 未登錄 -->
<div class="col-md-3 text-end">
<%= link_to '註冊', register_path, class: 'btn btn-outline-primary me-2' %>
<%= link_to '登入', login_path, class: 'btn btn-primary' %>
</div>
靜態頁面放進後,現在我們要考慮的是將其動態化,首先改造的是註冊頁面,我們用form_for 來做表單,這裏需要注意的是,在 devise 默認的字段裏沒有 username,我們需要加上
創建一個 migration 文件,用於向 User 模型添加 username 字段
rails g migration AddUsernameToUser username:string:uniq
uniq表示唯一
將這個 migration 遷移至數據庫
rails db:migrate
在 models/user.rb 中新增對 username 的驗證
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :username, presence: true, uniqueness: { case_sensitive: false }, length: { minimum: 3, maximum: 25 }
end
presence: true驗證:該屬性必須存在(不能為nil或空白字符串)uniqueness: { case_sensitive: false }驗證:該屬性的值必須是唯一的(即數據庫中不存在相同的值)。此外,該驗證規則將忽略大小寫,因此類似的兩個字符串,例如abc和ABC,將被認為是相等的length: { minimum: 3, maximum: 25 }驗證:該屬性的長度必須介於 3 到 25 個字符之間
修改註冊頁面視圖,新增用户名樣式
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
...
<div class="form-group mb-3">
<%= f.text_field :username, autofocus: true, autocomplete: "username",
class: "form-control form-control-lg",
placeholder: "用户名" %>
</div>
...
<% end %>
在改造時,我們還需要生成 devise 的控制器,讓表單在提交時前往正確的控制器處(因為我們定製了登錄註冊路徑,而不是用默認的,所以還要改造)
rails g devise:constroller -c # 生成所有 devise 的控制器
再在 config/routes.rb 中修改
...
devise_for :users, path: "", path_names: {
sign_in: "login",
sign_out: "logout",
sign_up: "register"
}, controllers: {
registrations: "users/registrations",
sessions: "users/sessions",
}
devise_scope :user do
get '/login' => 'devise/sessions#new'
get '/register' => 'devise/registrations#new'
end
...
如此,註冊頁面就改造完了,繼續改造登錄頁面
devise-i18n國際化
當我們做完登錄頁之後,提示報錯信息還都是英文的,這次需要引入 i18n 來做中文提示
老規矩,先安裝 devise-i18n gem
bundle add devise-i18n
在 config/application.rb 文件中添加如下代碼:
config.i18n.default_locale = "zh-CN"
執行 devise:i18n 生成中文命令
rails generate devise:i18n:locale zh-CN
再去config/locales/devise.zh-CN.yml 中修改不滿意的翻譯,如此就完成了國際化
如此我們已經完成了5個頁面,即首頁、文章詳情頁、登錄頁、註冊頁、寫文章頁,還剩下設置頁和個人頁
設置頁
如果説 article 和 user 是通過命令行來生成的,那麼接下來的兩個頁面(設置、個人頁),就是我們正常開發時的開發流程
先創建一個 Settings 控制器:
rails g controller Settings index
在 config/routes.rb 中新增一個 "seetings" (單數資源)資源路由,開放 show 和 update :
resource :settings, only: [:show, :update]
創建 app/views/settings/index.html.erb 頁面,加上 bootstrap 樣式,settings 的靜態頁面就能訪問了
看靜態頁面我們就知道,users 數據中我們還缺少頭像(avatar)和簡介(bio),所以我們需要在 users 表中新增兩個字段
生成一個遷移文件,該文件添加 avatar 和 bio 列到 users 表中
rails g migration AddAvatarAndBioToUsers avatar:string bio:string
運行 rails db:migrate 修改數據庫中的表
rails db:migrate
接着我們前往 settings_controller.rb 控制器,修改為後續渲染頁面
class SettingsController < ApplicationController
before_action :authenticate_user!
before_action :set_user
def show
end
def update
if @user.update(user_params)
# 後續跳轉到個人設置頁面
redirect_to root_path
flash[:notice] = '修改成功'
else
render :show
end
end
private
def set_user
@user = current_user
end
def user_params
params.require(:user).permit(:username, :email, :avatar, :bio)
end
end
同樣,視圖也要修改,刪除更改密碼一欄,為什麼呢?因為 devise 中修改密碼,需要輸入原密碼,是很麻煩的,筆者嘗試了一下,放棄了
個人頁
我們繼續做個人頁,也是我們的最後一個頁面,雖然還有很多細節(比如評論、點贊文章、收藏文章等邏輯),但是從頁面的角度講,這就是最後一個頁面了
先建立控制器
rails g controller profile
在 config/routes.rb 處,新增一個路由映射
get '/:name', to: 'profile#show', as: :profile
前往views/common/_header.html.erb 處,修改原來的 username 視圖
<li class="nav-item">
<%= link_to profile_path(current_user.username), class: "nav-link px-2" do %>
<%= image_tag current_user.avatar, alt: "avatar", class: "user-pic" %>
<%= current_user.username %>
<% end %>
</li>
然後我們去 view/profile/show.html.erb 寫好我們的靜態頁面,7個頁面就此完成,但這隻完成了一半。接下來,我們要對頁面進行改造,加上文章評論、點贊/取消點贊、關注/取消用户等等功能
如此,已經耗盡一天功夫,休息一晚,明天再戰
系列文章
- 前端學Ruby:前言
- 前端學 Ruby:安裝Ruby、Rails
- 前端學 Ruby:熟悉 Ruby 語法
- 前端學 Ruby:熟悉Rails
- 前端學 Ruby:唐詩API項目
- 前端學 Ruby:唐詩項目部署優化