2017/11/29

Ruby - 使用 Devise confirmable

Devise confirmable

當你想要認證註冊者的信箱時可以使用 confirmable

安裝方式請參考:https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users

以下說明一些實務上的可能會遇到的細節調整方式。

什麼時候會寄出信?

建立 user 時

在建立 user 時,會在呼叫 user.save 後寄信給 user。

user = User.create
user.save

user email 更新時

在編輯 user 時,若 email 有修改,會在呼叫 user.save 後寄信給 user。

user = User.find(params[:id])
user.email = 'QQ@QQ'
user.save

此時寫入的 email 會被保存到 unconfirmed_email,而原先的 email 欄位在 user 完成認證之前不會改變。

開發時測試寄信的方法

在開發時可能會希望不要真的寄出信件,此時可以使用 letter_opener,他會在需要寄信時,只將信件內容印在 console log 上。

設定方法是在 config/environments/development.rb 加入以下程式碼:

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

confirmable 自動測試

加入了 confirmable 之後可能會導致 test fail,因為 devise 嘗試 send mail 但是 test 環境下可能無法正確寄信。

避免寄出信件的方法

如果你希望在測試時不要寄信,如果你使用 FactoryBot 這個套件來生成 user,以下是跳過 email 驗證的方法:

FactoryBot.define do
  factory :user do
    after(:build)   { |u| u.skip_confirmation! }
  end
end

在不使用 FactoryBot 的情況下,跳過 email 驗證的方法:

user = User.new
user.skip_confirmation!
user.save

成功寄出信件的方法

如果你希望寄信,但是你沒有設定 host 值,那麼你會看見這個:

ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true

此時你需要加入以下內容至 config/environments/test.rb:

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

測試寄件內容

使用 ActionMailer::Base.deliveries.last 可以取得最後一次寄出的信件內容:

user = User.new
user.save
mail = ActionMailer::Base.deliveries.last

mail.from
mail.to
mail.subject
mail.body.to_s

因此可以對信件內容做測試。

模擬使用者完成認證

用 code 完成認證的方法

user = User.find(params[:id])
user.confirm

同一個認證連結被點擊第二次會發生什麼事?

當 user 點擊第二次認證信連結時,預設是會顯示「 Email was already confirmed, please try signing in. 」字樣。可以透過自訂 controller 去修改預設行為

怎麼修改認證信內容?

改 template 改 template 路徑

自定義寄信路徑

class DeviseMailer < Devise::Mailer   
  helper :application # gives access to all helpers defined within `application_helper`.
  include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`

  def headers_for(action, opts)
    super.merge!({template_path: '/users/mailer'}) # this moves the Devise template path from /views/devise/mailer to /views/users/mailer
  end

  # def confirmation_instructions(record, token, opts={})
  #   headers["Custom-header"] = "Bar"
  #   opts[:from] = 'my_custom_from@domain.com'
  #   opts[:reply_to] = 'my_custom_from@domain.com'
  #   super
  # end
end

參考資料:

測試寄信的方法 http://guides.rubyonrails.org/testing.html#testing-your-mailers

阻止修改mail時的認證:https://coderwall.com/p/7_yh8q/skip-devise-email-confirmation-on-update

沒有留言: