2018/1/16

第二十八天:建立管理後台

應觀眾要求,今天我們作一個管理後台,讓我們可以在網頁上管理關鍵字。

在開始之前,先大概說明一下今天要學習的範圍有哪些:

  • 網頁的呈現需要使用 HTML 和 CSS
  • 既然是後台,就要作登入功能

我們作的網站到目前為止沒有碰過任何的 HTML 和 CSS,突然要寫個管理後台也許會很吃力。不過還好是作後台,不需要多美觀。

使用產生器製作後台

幸好 Rails 有一個內建指令直接生成網頁,不一定要自己寫。

指令是 rails generate scaffold 資料模型名稱 和欄位們

rails g scaffold keyword_mapping channel_id keyword message --skip

後面的 --skip 是指定當發生衝突時應該略過。衝突的意思是指 rails 想新增一個檔案,剛好在目錄裡已經有個同名的檔案。

D:\只要有心,人人都可以作卡米狗\ironman>rails g scaffold keyword_mapping channel_id keyword message --skip
      invoke  active_record
        skip    db/migrate/20180115144538_create_keyword_mappings.rb
   identical    app/models/keyword_mapping.rb
      invoke    test_unit
   identical      test/models/keyword_mapping_test.rb
        skip      test/fixtures/keyword_mappings.yml
      invoke  resource_route
       route    resources :keyword_mappings
      invoke  scaffold_controller
      create    app/controllers/keyword_mappings_controller.rb
      invoke    erb
      create      app/views/keyword_mappings
      create      app/views/keyword_mappings/index.html.erb
      create      app/views/keyword_mappings/edit.html.erb
      create      app/views/keyword_mappings/show.html.erb
      create      app/views/keyword_mappings/new.html.erb
      create      app/views/keyword_mappings/_form.html.erb
      invoke    test_unit
      create      test/controllers/keyword_mappings_controller_test.rb
      invoke    helper
      create      app/helpers/keyword_mappings_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/keyword_mappings/index.json.jbuilder
      create      app/views/keyword_mappings/show.json.jbuilder
      create      app/views/keyword_mappings/_keyword_mapping.json.jbuilder
      invoke  test_unit
      create    test/system/keyword_mappings_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/keyword_mappings.coffee
      invoke    scss
      create      app/assets/stylesheets/keyword_mappings.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss

D:\只要有心,人人都可以作卡米狗\ironman>

以下說明到底生成了什麼東西。

生成 Routes

他會在 config/routes.rb 生成一個 resource:

resources :keyword_mappings

這是資源(resource),提供一個資源的存取所需要的網址和 Controller 的對應。

這行會生成 8 組網址與 7 個 Controller Action 的對應,可以使用 rails routes 觀察:

D:\只要有心,人人都可以作卡米狗\ironman>rails routes
                 Prefix Verb   URI Pattern                          Controller#Action
       keyword_mappings GET    /keyword_mappings(.:format)          keyword_mappings#index
                        POST   /keyword_mappings(.:format)          keyword_mappings#create
    new_keyword_mapping GET    /keyword_mappings/new(.:format)      keyword_mappings#new
   edit_keyword_mapping GET    /keyword_mappings/:id/edit(.:format) keyword_mappings#edit
        keyword_mapping GET    /keyword_mappings/:id(.:format)      keyword_mappings#show
                        PATCH  /keyword_mappings/:id(.:format)      keyword_mappings#update
                        PUT    /keyword_mappings/:id(.:format)      keyword_mappings#update
                        DELETE /keyword_mappings/:id(.:format)      keyword_mappings#destroy
             kamigo_eat GET    /kamigo/eat(.:format)                kamigo#eat
 kamigo_request_headers GET    /kamigo/request_headers(.:format)    kamigo#request_headers
    kamigo_request_body GET    /kamigo/request_body(.:format)       kamigo#request_body
kamigo_response_headers GET    /kamigo/response_headers(.:format)   kamigo#response_headers
   kamigo_response_body GET    /kamigo/response_body(.:format)      kamigo#show_response_body
    kamigo_sent_request GET    /kamigo/sent_request(.:format)       kamigo#sent_request
         kamigo_webhook POST   /kamigo/webhook(.:format)            kamigo#webhook

7 個 Action 分別為 index, create, new, edit, show, update, destroy,接下來說明各個 Action 的功能:

以下屬於 GET request,這些都是網頁:

  • index:列表頁
  • new:新增資料頁
  • show:檢視資料頁
  • edit:編輯資料頁

以下非 GET request,都是請求資料變更:

  • create:請求新增資料
  • update:請求更新資料
  • destroy:請求刪除資料

生成 Controller

生成了一個 Controller 在:app/controllers/keyword_mappings_controller.rb。7 個對應的 Action 都寫好了,這裡就不多介紹。

生成 View

生成了一整個資料夾的 View,其中最重要的 4 個:

app/views/keyword_mappings/index.html.erb
app/views/keyword_mappings/edit.html.erb
app/views/keyword_mappings/show.html.erb
app/views/keyword_mappings/new.html.erb

這就是那些 GET request 會用到的網頁檔,也都寫好了。

實測

既然都寫好了就來試用看看,先執行網頁伺服器:

rails s

然後開啟網頁 http://localhost:3000/keyword_mappings

index 列表頁

new 新增資料頁

隨便亂填:

show 檢視資料頁

所以其實不考慮美觀性的話,其實後台只要一個指令就完成了。

建立登入功能

使用知名套件 devise 來作。

我相信現在的你如果沒有英文閱讀障礙,應該已經能看懂這個使用說明

總而言之先在 Gemfile 加這行:

gem 'devise'

然後在小黑框打 bundle install 安裝套件。

裝好之後使用 devise 提供的產生器指令進行初始化: rails generate devise:install

D:\只要有心,人人都可以作卡米狗\ironman>rails generate devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================

D:\只要有心,人人都可以作卡米狗\ironman>

他說有幾個步驟產生器沒搞頭,必須手動進行。我們先不管他,等到真正出問題再回頭來解決。

使用產生器產生用戶資料模型:

rails generate devise user
D:\只要有心,人人都可以作卡米狗\ironman>rails generate devise user
      invoke  active_record
      create    db/migrate/20180115152537_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

D:\只要有心,人人都可以作卡米狗\ironman>

跟剛剛的 scaffold 差不多,該生的都生好了。

註冊頁:http://localhost:3000/users/signup 登入頁:http://localhost:3000/users/signin

關閉註冊功能

我們要將註冊功能關閉,如果大家都能註冊,那還要後台幹嘛?

app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end

刪除 :registerable,

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable,
         :recoverable, :rememberable, :trackable, :validatable
end

登入後才能管理關鍵字

我們希望只有登入後的人才能進入管理關鍵字的頁面。

app/controllers/keyword_mappings_controller.rb 加入:

before_action :authenticate_user!

看起來像這樣:

class KeywordMappingsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_keyword_mapping, only: [:show, :edit, :update, :destroy]

  ...下略

這時候開啟網址:http://localhost:3000/keyword_mappings,就會因為尚未登入,而被引導至登入頁。

發布流程

  • 上傳程式碼
  • Heroku 上的資料庫遷移

關閉了註冊功能後要怎麼新增自己的帳號?

使用 rails console 連上去新增帳號:

heroku run rails console

連上後會是 rails console 的樣子:

D:\只要有心,人人都可以作卡米狗\ironman>heroku run rails console
Running rails console on people-all-love-kamigo... up, run.2165 (Free)
Loading production environment (Rails 5.1.4)
irb(main):001:0>

寫一行程式碼新增資料:

User.create(email:'kamigo.service@gmail.com', password:'kamigo')

會有一些 SQL 的訊息:

irb(main):001:0> User.create(email:'kamigo.service@gmail.com', password:'kamigo')
D, [2018-01-15T15:42:28.307402 #4] DEBUG -- :    (6.0ms)  BEGIN
D, [2018-01-15T15:42:28.313291 #4] DEBUG -- :   User Exists (2.1ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "kamigo.service@gmail.com"], ["LIMIT", 1]]
D, [2018-01-15T15:42:28.317361 #4] DEBUG -- :   SQL (1.9ms)  INSERT INTO "users" ("email", "encrypted_password", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["email", "kamigo.service@gmail.com"], ["encrypted_password", "$2a$11$EyR.yuDYI3J2s9/Q8Etk5evQzsz2bGAPdvdcr.xmFQbzYbBPQk/kK"], ["created_at", "2018-01-15 15:42:28.313883"], ["updated_at", "2018-01-15 15:42:28.313883"]]
D, [2018-01-15T15:42:28.320139 #4] DEBUG -- :    (2.0ms)  COMMIT
=> #<user id:="" 1,="" email:="" "kamigo.service@gmail.com",="" created_at:="" "2018-01-15="" 15:42:28",="" updated_at:="" 15:42:28"="">
irb(main):002:0>

看到倒數第二行:

=> #<user id:="" 1,="" email:="" "kamigo.service@gmail.com",="" created_at:="" "2018-01-15="" 15:42:28",="" updated_at:="" 15:42:28"="">

就表示建立好帳號了。

線上實測

https://people-all-love-kamigo.herokuapp.com/keyword_mappings

大家可以用我的帳號登入看看。

帳號:kamigo.service@gmail.com 密碼:kamigo

本日重點

  • 學會使用 scaffold
  • 學會作登入系統

你們可以透過閱讀 scaffold 產生出來的程式碼來學習 HTML 和 Controller Action 的寫法。這跟學英文一樣,看到不懂的單字就 Google,這單字量還比英文少超多,大概 100~200 個字而已。

明天講怎麼發公告。

沒有留言: