Cài đặt Angular SPA trong Rails với Devise và Bootstrap
Angular là một bộ Javascript Framework rất mạnh và thường được sử dụng để xây dựng project Single Page Application (SPA). Nó hoạt động dựa trên các thuộc tính mở rộng HTML (các atributes theo quy tắc của Angular). Đây là một Framework mã nguồn mở hoàn toàn miễn phí. Trong bài viết này sẽ đề cập ...
Angular là một bộ Javascript Framework rất mạnh và thường được sử dụng để xây dựng project Single Page Application (SPA). Nó hoạt động dựa trên các thuộc tính mở rộng HTML (các atributes theo quy tắc của Angular). Đây là một Framework mã nguồn mở hoàn toàn miễn phí. Trong bài viết này sẽ đề cập cách setup cơ bản Angular trong Rails với Devise và Bootstrap
1. Cài đặt BackEnd:
- Thêm các gem cần thiết:
gem 'devise' gem 'angular-rails-templates' #=> cho phép để file html trong folder assets/javascript gem 'active-model-serializers' gem 'bootstrap-sass', '~> 3.3.6'
- Chạy bundle install, khởi tạo devise rails g devise:install và tạo database với bảng User,
rails g migration AddUsernametoUsers username:string:uniq
- Tạo serializer cho model user : rails g serializer user
- Angular sẽ nhận gía trị user kiểu json, nên để đảm bảo DeviseController trả về gía trị phù hợp, ta cần config:
#config/application.rb class Application < Rails::Application config.to_prepare do DeviseController.respond_to :html, :json end end
- Thêm các setting cần thiết:
#config/routes.rb devise_for :users root 'application#index' #app/controllers/application_controller.rb class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? skip_before_action :verify_authenticity_token respond_to :json def index render 'application/index' end protected def configure_permitted_parameters added_attrs = [:username, :email, :password, :password_confirmation, :remember_me] devise_parameter_sanitizer.permit :sign_up, keys: added_attrs devise_parameter_sanitizer.permit :account_update, keys: added_attrs end end
- Trong user_controller.rb , đảm bảo gía trị response là JSON
class UsersController < ApplicationController def show user = User.find(params[:id]) render json: user end end
- Config asset pipeline:
#app/assets/javascript/application.js //= require jquery //= require jquery_ujs //= require angular //= require angular-ui-router //= require angular-devise //= require angular-rails-templates //= require bootstrap-sprockets //= require_tree .
Nhớ bỏ require turbolinks
2. Cài đặt FrontEnd
- Ta đã cài gem angular-templates nên có thể giu file HTML trong assets/javascript
- Đây là cấu trúc cây của 1 app Angular
/javascript/controllers/AuthCtrl.js /javascript/controllers/HomeCtrl.js /javascript/controllers/NavCtrl.js /javascript/directives/NavDirective.js /javascript/views/home.html /javascript/views/login.html /javascript/views/register.html /javascript/views/nav.html /javascript/app.js /javascript/routes.js
- Đầu tiên, khai bảo app trong app.js:
(function(){ angular .module('myApp', ['ui.router', 'Devise', 'templates']) }())
- Edit file Routes.js
angular .module('myApp') .config(function($stateProvider, $urlRouterProvider){ $stateProvider .state('home', { url: '/home', templateUrl: 'views/home.html', controller: 'HomeCtrl' }) .state('login', { url: '/login', templateUrl: 'views/login.html', controller: 'AuthCtrl', onEnter: function(Auth, $state){ Auth.currentUser().then(function(){ $state.go('home') }) } }) .state('register', { url: '/register', templateUrl: 'views/register.html', controller: 'AuthCtrl', onEnter: function(Auth, $state){ Auth.currentUser().then(function(){ $state.go('home') }) } }) $urlRouterProvider.otherwise('/home') })
$urlRouterProvider đảm bảo user không thể điều hướng tùy ý. Tiếp theo edit file home.html và HomeCtrl.js:
#home.html <div class="col-lg-8 col-lg-offset-2"> <h1>{{hello}}</h1> <h3 ng-if="user">Welcome, {{user.username}}</h3> </div> #HomeCtrl.js angular .module('myApp') .controller('HomeCtrl', function($scope, $rootScope, Auth){ $scope.hello = "Hello World" })
- Xây dựng màn hình authen:
# login.js <div class="col-lg-8 col-lg-offset-2"> <h1 class="centered-text">Log In</h1> <form ng-submit="login()"> <div class="form-group"> <input type="email" class="form-control" placeholder="Email" ng-model="user.email" autofocus> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Password" ng-model="user.password"> </div> <input type="submit" class="btn btn-info" value="Log In"> </form> </div> # register.js <div class="col-lg-8 col-lg-offset-2"> <h1 class="centered-text">Register</h1> <form ng-submit="register()"> <div class="form-group"> <input type="email" class="form-control" placeholder="Email" ng-model="user.email" autofocus> </div> <div class="form-group"> <input type="username" class="form-control" placeholder="Username" ng-model="user.username" autofocus> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Password" ng-model="user.password"> </div> <input type="submit" class="btn btn-info" value="Log In"> </form> <br> <div class="panel-footer"> Already signed up? <a ui-sref="home.login">Log in here</a>. </div> </div> #AuthCtrl angular .module('myApp') .controller('AuthCtrl', function($scope, $rootScope, Auth, $state){ var config = {headers: {'X-HTTP-Method-Override': 'POST'}} $scope.register = function(){ Auth.register($scope.user, config).then(function(user){ $rootScope.user = user alert("Thanks for signing up, " + user.username); $state.go('home'); }, function(response){ alert(response.data.error) }); }; $scope.login = function(){ Auth.login($scope.user, config).then(function(user){ $rootScope.user = user alert("You're all signed in, " + user.username); $state.go('home'); }, function(response){ alert(response.data.error) }); } })
Auth là dịch vụ được tạo bởi angular-device, cung cấp chức năng login và register (Auth.login(userParameters, config) và Auth.register(userParameters, config))
- Kết nối các thành phần với nhau:
#NavDirective.js angular .module('myApp') .directive('navBar', function NavBar(){ return { templateUrl: 'views/nav.html', controller: 'NavCtrl' } }) #nav.html <div class="col-lg-8 col-lg-offset-2"> <ul class="nav navbar-nav" > <li><a ui-sref="home">Home</a></li> <li ng-hide="signedIn()"><a ui-sref="login">Login</a></li> <li ng-hide="signedIn()"><a ui-sref="register">Register</a></li> <li ng-show="signedIn()"><a ng-click="logout()">Log Out</a></li> </ul> </div> #NavCtrl.js angular .module('myApp') .controller('NavCtrl', function($scope, Auth, $rootScope){ $scope.signedIn = Auth.isAuthenticated; $scope.logout = Auth.logout; Auth.currentUser().then(function (user){ $rootScope.user = user }); $scope.$on('devise:new-registration', function (e, user){ $rootScope.user = user }); $scope.$on('devise:login', function (e, user){ $rootScope.user = user }); $scope.$on('devise:logout', function (e, user){ alert("You have been logged out.") $rootScope.user = undefined }); })
sử dụng các link điều hướng ng-hide="signedIn()" và ng-click="logout()" và thêm các bộ nghe $scope để chạy các hành động khi các sự kiện devise xảy ra. Ngoài ra ta gọi Auth.currentuser() để khi controller được khởi tạo, chúng ta có thể kiểm tra đối tượng $rootScope.user và hiển thị link điều hướng thích hợp.
Trên đây là các cài đặt một app đơn gian sử dụng angular trong rails dùng Devise và Bootstrap.