Cài đặt Angular SPA trong Rails với Devise và Bootstrap
Bài đăng này đã không được cập nhật trong 7 năm
I. Giới thiệu
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
II. Cách sử dụng
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 deviserails 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 trongassets/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.
All rights reserved