---
title: 12th 鐵人賽 Day_10 問題中場休息-部落格的管理員系統
tags: 12th 鐵人賽
---
# 12th 鐵人賽 Day_10 問題中場休息-部落格的管理員系統
嗨!各位朋友大家好,打給後,歹嘎吼,胎尬喉,我是阿圓,一樣有請今天的one piece:

居然已經邁入第十天,我的挑戰也已經過了三分之一了,但我居然一行code都沒有放上來!!!這真的太母湯了!趕快來補救一下!那由於今天會放上我的部落格的程式碼,所以字數有點過長,問題就讓我放到明天來寫吧(所以明天會有兩個問題!)
## 定義路徑
```ruby=
# /routes.rb
Rails.application.routes.draw do
# 這邊為了測試,放了一個index給他,之後想要改成文章的首頁
root 'admins#index'
# 我不想要有預設的路徑,直接用最簡單的方式寫給他
get 'admins/sign_in', to: 'admins#sign_in'
post 'admins/sign_in', to: 'admins#login'
delete 'admins/sign_out', to: 'admins#sign_out'
end
```
## 建立views
```htmlmixed=
<!-- admins/views/index.html.erb -->
<h1>臨時首頁</h1>
<%= link_to '登入', admins_sign_in_path%>
<%= link_to '登出', admins_sign_out_path, method: "delete"%>
```
```htmlmixed=
<!-- admins/views/sign_in.html.erb -->
<h1>管理者登入</h1>
<%= form_for(@admin, url: admins_sign_in_path) do |f| %>
<div class="fields">
<%= f.label :account %>
<%= f.text_field :account, placeholder:'請輸入帳號' %>
</div>
<div class="fields">
<%= f.label :password, placeholder:'請輸入密碼' %>
<%= f.password_field :password %>
</div>
<%= f.submit "登入"%>
<% end %>
```
## 建立controller
`$ rails g controller admins`
接著定義action,將routes上的action寫上去,至於預設的路徑,就先不處理,之後有需要再來改。
```ruby=
def sign_in
#do something
end
def login
#do something
end
def sign_out
#do something
end
```
## 建立model
先建立model
`$ rails g model Admin account password:password`
Admin有兩個欄位,account 跟 password
```ruby=
# /admin.rb
class Admin < ApplicationRecord
# account password 必填
validates :account, presence: true, uniqueness: true
validates :password, presence: true
# 在create之前,將密碼加密
before_create :encrypt_password
end
```
自定義自己的密碼加密方式,要在Admin這邊的一個物件create之前將密碼加密,在下面 private 的寫下:
```ruby=
private
def encrypt_password
self.password = popper(password)
end
def popper(string)
string = 'cu' + string + 'te'
Digest::SHA1.hexdigest(string)
end
```
所謂 `popper` ,就是在密碼前後加些綴字,讓密碼更難破解(不過我都放上來了XD,就相當於無效了哈哈)。
## 更改controller裡的action
### sign_in
```ruby=
# /admins_controller.rb
# 在Admin的類別中,新增一個@admin的實體變數
def sign_in
@admin = Admin.new
end
```
現在就有畫面了:

### login
接著來定義,按下登入按鈕後,要進行的事情:
```ruby=
# /admins_controller.rb
def login
admin = Admin.login(admin_params)
# 確認資料庫裡是否有使用相同account和password的管理員
if admin
sign_in_admin(admin) #定義在下方,發session
redirect_to root_path, notice: '成功登入!'
else
redirect_to sign_in_admins_path, notice: '請輸入正確帳號密碼'
end
end
```
其中,第2行的 `login` 是為了要去比對資料庫裡是否有相同帳號密碼的使用者,所以將方法定義在 admin 的 model 裡面(所有的 admin 都有 login 的方法),如下:
```ruby=
# /admin.rb
def self.login(options)
if options[:account] && options[:password]
find_by(account: options[:account],
password: Digest::SHA1.hexdigest('cu' + options[:password] + 'te'))
end
end
```
上面做了什麼呢?有請圖解!

搞定了model的login方法,接著來繼續回來controller,在下面加上:
```ruby=
# /admins_controller.rb
private
def sign_in_admin(a)
session[:admin_token] = SecureRandom.uuid
# 這裡使用了SecureRandom的方法,他是一個在rails 裡寫好的module,所以要去最上面加上 require 'securerandom'
end
def admin_params
params.require(:admin).permit(:account, :password)
end
```
簡單解釋一下 `admin_params` 做的事情,是將是將登入頁面打過來的資訊,清洗後再傳給 server,若沒有經過 `permit`,在 `create` 資料的時候,就會得到下列畫面:

但因為我沒有放東西進去,`login` 這個 `action` 沒有建立新的資料,所以沒有寫,網頁不會噴錯(我把方法改成 `create,`才得到這個畫面!)
這就是所謂的 `Strong parameter`,若想了解其中運作的原理,請參閱[為你自己學 Ruby on Rails](https://railsbook.tw/chapters/13-crud-part-1.html#step06-create-candidate) 。
延續 `login` 的 `action` :若登入成功,就將使用者轉址到根目錄,若失敗重新導入 `sign_in` 的頁面。
### sign_out
直接把session清掉!
```ruby=
# /admins_controller.rb
def sign_out
sign_out_admin
redirect_to root_path, notice: '會員登出成功'
end
private
def sign_out_admin
session[:admin_token] = nil
end
```
目前這就是我實作管理員系統的流程,感謝各位看到這邊,若有任何建議,==我非常需要各位的指教==!謝謝大家!我們明天見!
