寫在開始之前
這次的主題是想搭配devise gem做出popup式的註冊頁面,效果可以參考Airbnb。而其中的實作又會涉及到ajax的使用,這樣的做法是希望將使用者輸入的資料透過javascript進行非同步傳送至後端,再將結果回傳至前端讓我們判斷下一步要做什麼,例如成功註冊就將會員導至首頁,註冊失敗就顯示出失敗的訊息。
看完這份教學,你會了解:
- 用現成的foundation gem快速產生popup頁面(gem裡面稱做Reveal)
- Hack原本devise gem的預設controller、方法與頁面(這部分比較麻煩ˊ ˋ)
- 使用Ajax傳資料、塞資料
- 使用Rails-i18n gem搭配model翻譯訊息
- 請先開好一個Rails專案,本範例中的專案名稱為learn_ajax,並有welcome controller & welcome/index.html.erb
- 在本文中寫給讀者看的註解會使用 % 符號
- 如果是終端機的指令前面會加上$,輸入時只需要輸入這個符號後的程式碼
上工啦
1. Gemfile中加入以下,然後跑bundle
gem 'devise'
2. 終端機中跑devise的generator
$ rails generate devise:install
% 這步驟會幫你生成一些基本的設定檔
3. 接著要產生 User model,以及在資料庫中生成欄位了
3. 接著要產生 User model,以及在資料庫中生成欄位了
$ rails generate devise User $ rake db:migrate
foundation是一個響應式的前端框架,裡面幫你包好了很多功能,只要添加在程式碼中就可以快速完成某個複雜功能,例如sticky navbar、reveal、carousel、responsive design等。相似的框架如bootstrap、semantic等等。而rails生態圈有人剛好幫我們把foundation的內容包成gem,因此我們只要bundle gem就可以使用了。
1. 在Gemfile中加入以下,並bundle
gem 'foundation-rails'
2. 跑以下指令以自動產生foundation相關檔案
$ rails g foundation:install
% 跑完後應該會有foundationandoverrides.scss & _setting.scss檔案
3. 在 assets/stylesheets/application.css 中加入foundation的css
2. 在Gemfile中刪除以下,並bundle
simple_form gem
2. 跑generator
% 最下面的foundation-popup div,是之後要塞popup程式碼的地方。
3. 在 assets/stylesheets/application.css 中加入foundation的css
*= require foundation_and_overrides4. 在 assets/javascripts/application.js 中加入foundation的js,並啟動
//= require foundation
$(function(){
$(document).foundation();
});
% 完成了3, 4步驟後接下來就有foundation的js & css可以使用了
turbolink gem 關閉
turbolink為Rails預設內建的gem,可以加速頁面的render。但這個gem很容易跟其他js有衝突,讓js動不了,因此在這裡我們先停止這個功能,以避免太複雜的情形。
1. 在 assets/javascripts/application.js 中刪除以下
//= require turbolinks
gem 'turbolinks'
simple_form gem
1. 在Gemfile中加入以下,並bundle
gem 'simple_form'
rails generate simple_form:install
新增註冊popup頁面
我們要做到以下:
i. 在welcome/index產生註冊連結
ii. 該連結會連至我們客製化的註冊頁面
1. 新增 views/welcome/signup.html.erb 頁面
<div class="reveal-modal custom-modal" id="signup" data-reveal data-close-on-click="true" data-animation-in="fade-in" data-animation-out="fade-out"> <h2>來看看如何用ajax進行註冊</h2> <div class="alert_info"></div> <%= simple_form_for User.new, as: :user, url: user_registration_path, html: { id: "registration_form" }, remote: true, format: :json do |f| %> <%= f.input :email %> <%= f.input :password %> <%= f.input :password_confirmation %> <div class="form-actions"> <%= f.button :submit %> </div> <% end %> <button class="close-button" data-close aria-label="Close reveal" type="button"> <span aria-hidden="true">×</span> </button> </div>
% 這裡東西比較多,我們一一解釋。當中看到有reveal字樣的,都和foundation reveal有關,照著打就可以產生一個popup的頁面,有興趣dig in的可以去翻foundation的docs。
% 最外面用 id="signup"包起來,這是等一下我們要用來呼叫這個popup的attribute。
% alert_info區域是之後要用來顯示錯誤訊息的區塊。
% simple form裡面是我們註冊所需要輸入的欄位。url指向註冊的路由;id: "registration_form"之後ajax會用到;remote: true是Rails內建的ajax helper,幫助我們送出ajax請求至後端;format: :json指定表單的內容以json的格式傳送。
% 最後面加上了一個close button。
2. 配置 welcome/index.html.erb
<h1>Welcome to this page</h1> <h2>Here we'll going to learn ajax from devise.</h2> <h3>If you are interested in it, just learn with me :)</h3> <a href="#" id="signup-link">Ajax註冊</a> <div id="foundation-popup"></div>% 加上了一個開啟註冊的popup連結,連結的地方用#代替,後面會用js驅動連結;連結的id是給js呼叫用的。
% 最下面的foundation-popup div,是之後要塞popup程式碼的地方。
3. 在 routes.rb加上路由,完成後應如下面
Rails.application.routes.draw do root 'welcome#index' devise_for :users get 'welcome/signup', to: 'welcome#signup' end
% 這步驟是手動指定路由,指定當網址為 welcome/signup 形式時,交給welcome controller裡面的signup action來動作。
4. 在 welcome_controller.rb 裡面加上action,完成後如下
5. 使用js驅動連結,在 javascripts/welcome.js 裡面加入
% 上面會看到開啟的方式有兩個,一個是前面提到的ajax拿取資料並開啟,而另一個則是當已經開啟過一次signup之後,signup的程式碼就已經存在首頁了,因此不需要再向後端拿取,只要將他開啟就好。
當以上都完成後,去點連結應該就會出現註冊的popup。接著要來實作註冊表單輸入後的相對應動作。
1. 新增 controllers/registrations_controller.rb,並做修改
原本devise的 registrations_controller.rb 裡面的create action程式碼如下
2. 修改routes.rb,讓程式吃我們客製化的registrations controller,修改完應如以下
至此,基本上整套註冊流程就完成了。從按註冊連結會跳出註冊的popup視窗,可以在表單裡輸入資料,按下submit按鍵後資料會以ajax的方式傳送到後端驗證並儲存,如果成功就關掉popup並重整頁面,如果失敗就將失敗的錯誤訊息印出來,讓使用者可以修正。所以大家可以試試看故意不輸入email或是密碼不相同之類,測試能不能印出正確的錯誤的訊息。但你應該會發現印出來的錯誤是「英文版」的,沒錯,因為我們還沒設定i18n這步驟,因此接下來我們要將訊息轉化成中文。
1. 在Gemfile中加入 rails_i18n gem並bundle
4. 新增 config/locales/devise.zh-TW.yml 並到這裡複製中文的devise訊息,並貼上存檔。
% 這個檔案會讓devise的訊息都轉換為中文。之後註冊過程中如果有錯誤訊息的話就會進行翻譯並組合,可能得到的錯誤會像是:密碼 不能是空白字元。
4. 在 welcome_controller.rb 裡面加上action,完成後如下
class WelcomeController < ApplicationController def index end def signup render layout: false end end% 加上signup這個action,運作原理是當我向welcome controller請求signup action時,signup action會執行該段的程式碼,並且render相對應的 welcome/signup.html.erb給前端。而裡面設定 render layout: false,代表我只需要render signup.html.erb裡面程式碼就好,不需要包含application.html.erb裡面的layout。
5. 使用js驅動連結,在 javascripts/welcome.js 裡面加入
// open foundation signup modal $(function() { $("#signup-link").click(function(event) { event.preventDefault(); if ($("#signup").length > 0) { $("#signup").foundation("open"); } else { $.ajax({ url: '/welcome/signup', type: 'GET', success: function(response) { $("#foundation-popup").append(response) signup = new Foundation.Reveal($("#signup")); signup.open(); }, error: function(xhr) { console.log(xhr) } }); } }); });% 整段的js意思是監聽 #signup-link 這個連結如果有被按的話,那麼就以popup的方式顯示signup.html.erb。怎麼顯示呢?我們會利用ajax的方式去向後端拿取signup.html.erb的程式碼(else那段),首先指定拿取的網址為/welcome/signup,這會對應到前面設定的路由,將這樣的請求交給welcome controller的signup action去做回應,接著如果回應成功的話我們就用success將回應(response)拿到前端,response的內容就是signup.html.erb裡面的程式碼。再來將程式碼塞入welcome/index.html.erb的 #foundation-popup div裡面,至此,已經讓signup程式碼在首頁出現了,但還沒變成foundation reveal的物件,因此我們抓取 #signup(就是signup.html.erb最外面的div的id),並new成一個reveal的物件,接著再開啟這個物件,就可以看到popup視窗出現了。
% 上面會看到開啟的方式有兩個,一個是前面提到的ajax拿取資料並開啟,而另一個則是當已經開啟過一次signup之後,signup的程式碼就已經存在首頁了,因此不需要再向後端拿取,只要將他開啟就好。
當以上都完成後,去點連結應該就會出現註冊的popup。接著要來實作註冊表單輸入後的相對應動作。
表單輸入後資料的處理
前面已經將表單設為remote,以ajax的方式將資料送到後端,格式為json。但原本devise已經將registrations_controller整包都寫好了,算是一個黑盒子,而這個黑盒子裡面的程式碼並不完全符合我們的需求,因此我們必須override這個controller,讓他可以依我們的需求回應json格式的資料到前端。
1. 新增 controllers/registrations_controller.rb,並做修改
原本devise的 registrations_controller.rb 裡面的create action程式碼如下
class Devise::RegistrationsController < DeviseController def create build_resource(sign_up_params) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message! :notice, :signed_up sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}" expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end endoverride的registrations_controller.rb如下
class RegistrationsController < Devise::RegistrationsController # Inherited from Devise::RegistrationsController. # For overwriting the respond format from html to json through ajax. def create build_resource(sign_up_params) if resource.save if resource.active_for_authentication? set_flash_message :notice, :signed_up if is_navigational_format? sign_up(resource_name, resource) respond_to do |format| format.json { render json: {}, status: :ok } format.html { respond_with resource, location: after_sign_up_path_for(resource) } end else set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? expire_session_data_after_sign_in! respond_to do |format| format.json { render json: {}, status: :ok } format.html { respond_with resource, location: after_sign_up_path_for(resource) } end end else clean_up_passwords resource respond_to do |format| format.json { render json: resource.errors.full_messages, status: :unprocessable_entity } format.html { respond_with resource } end end end end
% 只override create action,因為我們需要客製化的是送出表單、create user完後的動作。這邊的code還沒refactor,大家有閒暇時間可以試試看。
% 如果user成功儲存的話就回應format.json,裡面回傳一個空的hash&200的status code。如果儲存失敗的話就回應出錯的訊息,errors.full_messages 是Rails ActiveModel預設的方法,會顯示出欄位驗證時的錯誤訊息。
2. 修改routes.rb,讓程式吃我們客製化的registrations controller,修改完應如以下
Rails.application.routes.draw do root 'welcome#index' devise_for :users, controllers: { registrations: "registrations" } get 'welcome/signup', to: 'welcome#signup' end3. 接著要接收從後端傳回來的訊息,我們在 welcome.js 裡寫進以下
// Show signup error messages in popup modal $(document).on("submit", "#registration_form", function(e) { $("input[type=submit]").prop("disabled", true); }).on("ajax:success", "#registration_form", function(e, data, status, xhr) { $("input[type=submit]").prop("disabled", false); $("#signup").foundation("close"); location.reload(); }).on("ajax:error", "#registration_form", function(e, data, status, xhr) { $("input[type=submit]").prop("disabled", false); $(".alert_info").empty(); for (var key in data.responseJSON) { $(".alert_info").append("<p>"+data.responseJSON[key]+"</p>"); $(".alert_info").css("background-color", "#F88E8B"); } });% 這裡用了另外一種方法實作ajax,大家只要先照做即可。我們監聽註冊表單submit的這個動作,當表單送出去後就會由前面override的registrations controller進行處理,接著如果成功儲存user時回傳的json資料就會由"ajax:success"處理,將popup關閉並進行頁面重整。如果user儲存失敗就會由"ajax:error"處理,而這邊會把錯誤的訊息印出來,並塞入popup的 ".alert-info"裡面。
至此,基本上整套註冊流程就完成了。從按註冊連結會跳出註冊的popup視窗,可以在表單裡輸入資料,按下submit按鍵後資料會以ajax的方式傳送到後端驗證並儲存,如果成功就關掉popup並重整頁面,如果失敗就將失敗的錯誤訊息印出來,讓使用者可以修正。所以大家可以試試看故意不輸入email或是密碼不相同之類,測試能不能印出正確的錯誤的訊息。但你應該會發現印出來的錯誤是「英文版」的,沒錯,因為我們還沒設定i18n這步驟,因此接下來我們要將訊息轉化成中文。
加入i18n
gem 'rails-i18n'2. 修改 config/application.rb ,設定zh-TW為預設語言,完成後應如以下
module LearnAjax class Application < Rails::Application # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. config.i18n.default_locale = "zh-TW" # Do not swallow errors in after_commit/after_rollback callbacks. config.active_record.raise_in_transactional_callbacks = true end end3. 新增 config/locales/user.zh-TW.yml
zh-TW: activerecord: attributes: user: email: "E-mail" password: "密碼" password_confirmation: "密碼確認"% 這個檔案會讓程式知道user model的幾個欄位相對應的中文是什麼,當在組合錯誤訊息時就會把欄位翻譯成中文。
4. 新增 config/locales/devise.zh-TW.yml 並到這裡複製中文的devise訊息,並貼上存檔。
% 這個檔案會讓devise的訊息都轉換為中文。之後註冊過程中如果有錯誤訊息的話就會進行翻譯並組合,可能得到的錯誤會像是:密碼 不能是空白字元。
完結
至此已經完成了一套完整的popup註冊流程,從一開始讓welcome的註冊連結能夠叫出popup註冊頁面;再來註冊表單能以ajax的方式與後端溝通,並將結果回傳回頁面;最後翻譯錯誤訊息。接著登入的頁面也可以如法炮製,就留給大家當作功課了!如果有任何問題都歡迎留言詢問,或是透過其他方法找到我問哈哈,會盡可能把我會的分享出來。參考資料
- https://www.airbnb.com.tw/
- https://github.com/plataformatec/devise
- https://github.com/zurb/foundation-rails/tree/master/vendor/assets
- http://api.jquery.com/jquery.ajax/
- https://github.com/plataformatec/simple_form
Bursa
回覆刪除Mersin
izmir
Rize
Antep
GH8
tekirdağ
回覆刪除tokat
elazığ
adıyaman
çankırı
4XQ3WS
bingöl
回覆刪除elazığ
hakkari
sakarya
erzincan
OSHQ
görüntülü show
回覆刪除ücretlishow
LZ8T
0C35B
回覆刪除trenbolone enanthate for sale
Paribu Güvenilir mi
order fat burner
Ağrı Evden Eve Nakliyat
Kırşehir Evden Eve Nakliyat
Uşak Evden Eve Nakliyat
winstrol stanozolol for sale
order anapolon oxymetholone
buy turinabol
A76C0
回覆刪除Bingöl Şehir İçi Nakliyat
Mardin Parça Eşya Taşıma
Probit Güvenilir mi
Tekirdağ Evden Eve Nakliyat
Ünye Organizasyon
Siirt Şehir İçi Nakliyat
Trabzon Şehir İçi Nakliyat
Muş Şehirler Arası Nakliyat
Hotbit Güvenilir mi
DC380
回覆刪除Kripto Para Nedir
Clubhouse Takipçi Hilesi
Kripto Para Oynama
Mith Coin Hangi Borsada
Binance Hangi Ülkenin
Binance Madencilik Nasıl Yapılır
Referans Kimliği Nedir
Tiktok İzlenme Hilesi
Referans Kimliği Nedir