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](http://localhost:3000/keyword_mappings): ### index 列表頁 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEist8IdgbyY3iAIGlOyofKz1eCnlRALx4SRUXGxlWhdzor1anPL8AvYbf9NuWaOJcmEr3pZLcr0eqLOJG_QNoxpmzsQPQNm5RDYPVXUukTpM4A7TGRsKqx_U_Gbh57VDIKGNLtBt0oIMNM/s1600/1.jpg) ### new 新增資料頁 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAQEbyfGqL9bOS5Jii-T2ovBPGBvgninU-HovOPbFaU3sQcKcaRWII3sPjce9droyLKCJEzKbaE9Bsv2n2JknSVhXTF99JMZmyFHiyXgYb6HamLGq5pm_D420ZdboEkF4blIJYFK5Whb0/s1600/2.jpg) 隨便亂填: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-1GgB1iT6XwiUq92wHqLCYcn5gbDaS6AJqhO3qHQT3BubyklAHFTq0Q3bz-lNH6dOiZxW5Kejc5BYcT2yHKl_sxSobzHpE1RRGTWL3Yq5T2CaOgyPt-yFoVjAz8Rzox-Y3SKWrfSIaCM/s1600/3.jpg) ### show 檢視資料頁 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCEGVY_kVAgDVOCwh5BSo9g3DEpfqcl9OUG3l3cN-NKNDHQe15EfGIndU3xtydKWlb4SoY3t4pwsmXf7F8aVovY1G16_ft24cIzhMXDSMle8UmjxU8EmK6W7KubR7b7l7-FmoW9rPe1KQ/s1600/4.jpg) 所以其實不考慮美觀性的話,其實後台只要一個指令就完成了。 # 建立登入功能 使用知名套件 [devise](https://github.com/plataformatec/devise) 來作。 我相信現在的你如果沒有英文閱讀障礙,應該已經能看懂這個[使用說明](https://github.com/plataformatec/devise#getting-started)。 總而言之先在 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:

<%= notice %>

<%= alert %>

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/sign_up](http://localhost:3000/users/sign_up) 登入頁:[http://localhost:3000/users/sign_in](http://localhost:3000/users/sign_in) # 關閉註冊功能 我們要將註冊功能關閉,如果大家都能註冊,那還要後台幹嘛? 在 `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](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 => # irb(main):002:0> ``` 看到倒數第二行: ``` => # ``` 就表示建立好帳號了。 # 線上實測 [https://people-all-love-kamigo.herokuapp.com/keyword_mappings](https://people-all-love-kamigo.herokuapp.com/keyword_mappings): 大家可以用我的帳號登入看看。 帳號:kamigo.service@gmail.com 密碼:kamigo # 本日重點 - 學會使用 scaffold - 學會作登入系統 你們可以透過閱讀 scaffold 產生出來的程式碼來學習 HTML 和 Controller Action 的寫法。這跟學英文一樣,看到不懂的單字就 Google,這單字量還比英文少超多,大概 100~200 個字而已。 明天講怎麼發公告。

沒有留言: