iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
0
自我挑戰組

Ruby on Rails 新手的30個問題!系列 第 10

Day_10 問題中場休息 & 部落格的管理員系統

嗨!各位朋友大家好,打給後,歹嘎吼,胎尬喉,我是阿圓,一樣有請今天的one piece:

(我也想拿可樂當燃料,還不會轉換成我的熱量!!!)

鐵人賽已經邁入第十天,我的挑戰也已經過了三分之一了,但我居然 一行code都沒有放上來!!! 這真的太母湯了!趕快來補救一下!(其實是覺得放上自己寫的程式碼太羞恥才拖到今天QQ)

貼心提醒: 由於今天會放上我的部落格的程式碼,字數有點過長(爆炸長!),問題就讓我放到明天來寫吧(所以明天會有兩個問題!)

定義路徑

有登入、登出的動作,但不會有註冊的動作,畢竟部落格只有我一個人是管理者,打算直接用後台寫進去:
(感覺有點怪怪der,若有問題之後再來改XD")

# /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

<!-- admins/views/index.html.erb -->
<h1>臨時首頁</h1>

<%= link_to '登入', admins_sign_in_path%>
<%= link_to '登出', admins_sign_out_path, method: "delete"%>
<!-- 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 %>

這裡是用form_for來建立登入的表單,畫面如下:

建立controller

$ rails g controller admins
接著定義action,將routes上的action寫上去:

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

# /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 的寫下:

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

# /admins_controller.rb
# 在Admin的類別中,新增一個@admin的實體變數
  def sign_in
    @admin = Admin.new
  end

login

接著來定義按下登入按鈕後,要進行的事情:

# /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 的方法),如下:

# /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,在下面加上:

# /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 資料的時候,就會得到下列畫面:

這就是所謂的 Strong parameter 問題,等待明天揭曉,若想先睹為快,請參閱為你自己學 Ruby on Rails

但因為login 這個 action 沒有建立新的資料,所以就算沒有寫,網頁也不會噴錯(我把方法改成 create,才得到這個畫面!)

sign_out

直接把session清掉!

# /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

目前這就是我實作管理員系統的流程,感謝各位看到這邊,若有任何建議,我非常需要各位的指教
謝謝大家!我們明天見!


上一篇
Day_09 sessions in Rails?
下一篇
Day_11 erb? form helper? strong parameter?
系列文
Ruby on Rails 新手的30個問題!30

尚未有邦友留言

立即登入留言