Integrate AngularJS to Rails 4.0
Dựa trên mô hình MVC, Ruby on Rails có khả năng tạo ra được một website hoàn chỉnh từ Database cho tới View. Tuy nhiên, với những ứng dụng có quy mô lớn hơn, việc server-side phải đảm nhiệm đủ cả 3 phần Model, View, Controller khiến cho hiệu năng hoạt động của server giảm đáng kể. Sự xuất hiện ...
Dựa trên mô hình MVC, Ruby on Rails có khả năng tạo ra được một website hoàn chỉnh từ Database cho tới View. Tuy nhiên, với những ứng dụng có quy mô lớn hơn, việc server-side phải đảm nhiệm đủ cả 3 phần Model, View, Controller khiến cho hiệu năng hoạt động của server giảm đáng kể. Sự xuất hiện của các framework dành cho client-side như EmberJs, BackboneJS, AngularJs đã phần nào giúp đỡ server đảm nhiệm phần view để có thể tương tác với người sử dụng. Trong bài tìm hiểu trước đó, chúng ta đã đi tìm hiểu về EmberJs trên RoR. Hôm nay, bài viết sẽ đi tìm hiểu về một ứng dụng khác, AngularJS. angular_rr AngularJS cung cấp một mô hình thu nhỏ của MVC trên phía người sử dụng. Giống như RoR, phần view đảm nhiệm việc thực hiên các thẻ HTML cùng với CSS trong khi Controller và Model đóng vai trò tương tác với dữ liệu. Điều khác biệt lớn nhất là thay vì tương tác trực tiếp với database như RoR, AngularJS sử dụng dữ liệu JSON lấy được từ server-side để hiển thị lên View. Rails ở đây đóng vai trò thuần túy là tương tác trực tiếp với database (MySQL, MongoDB, Sqlite..) và cung cấp các API cho phép trả ra dữ liệu dựa trên các request từ Client side. Việc phân chia độc lập 2 phần Back-end và Front-end không những giúp tăng hiệu năng hoạt đông của server mà còn giúp developer phát triển Client side có nhiều chức năng hơn. Trong phần tiếp theo, chúng ta sẽ đi sâu vào việc tạo một ứng dụng trực tiếp sử dụng RoR và AngularJS
Trong phần này, chúng ta sẽ đi xây dựng một ứng dụng tổng hợp tất cả các video trên Railscast. Có thể tham khảo ứng dụng trên github: https://github.com/ducthien1490/angular_railscast
2.1 Khởi tạo
Các khởi tạo cơ bản:
- Tạo application:
railsnewangularrailscastrails new angular_railscast railsnewangularrailscastcd angular_railscas
- Gemfile:
source "https://rubygems.org" gem "rails", "4.1.2" gem "sqlite3" gem "sass-rails", "~> 4.0.3" gem "uglifier", ">= 1.3.0" gem "coffee-rails", "~> 4.0.0" gem "turbolinks" gem "jbuilder", "~> 2.0" gem "sdoc", "~> 0.4.0", group: :doc gem "spring", group: :development gem "feedjira" gem "pry-rails"
- Tạo migration, controller và model:
$rails g resource screencast title summary:text duration link published_at:datetime source video_url $rake db:migrate app/models/screencast.rb:
class Screencast < ActiveRecord::Base validates_presence_of :title, :summary, :duration, :link, :published_at, :source, :video_url validates_uniqueness_of :video_url end
- Import data từ Railscast sử dụng Feedjia:
lib/screencast_importer.rb:
require "feedjira" class ScreencastImporter def self.import_railscasts Feedjira::Feed.add_common_feed_entry_element(:enclosure, :value => :url, :as => :video_url) Feedjira::Feed.add_common_feed_entry_element( 'itunes:duration', :as => :duration) feed = Feedjira::Feed.fetch_and_parse( "http://feeds.feedburner.com/railscasts") feed.entries.each do |entry| title = entry.title.gsub(/^#d+s/, ') Screencast.where(video_url: entry.video_url). first_or_create( title: title, summary: entry.summary, duration: entry.duration, link: entry.url, published_at: entry.published, source: "railscasts" ) end Screencast.where(source: 'railscasts').count end end
lib/tasks/sample_date.rake:
require "screencast_importer" namespace :screencast_sync do desc "Sync all Railscast videos" task :railscasts => :environment do total = ScreencastImporter.import_railscasts puts "There are #{total} videos from Railscasts" end end
Chạy rake để tạo dữ liệu mẫu:
rake screencast_sync:railscasts
2.2 Xây dựng API ở server-side
Định nghĩa routes
config/routes.rb:
Rails.application.routes.draw do scope :api do get "/screencasts(.:format)" => "screencasts#index" get "/screencasts/:id(.:format)" => "screencasts#show" end end
Controller
app/controllers/screencasts_controller.rb:
class ScreencastsController < ApplicationController def index render json: Screencast.all end def show render json: Screencast.find(params[:id]) end end
Controller được viết tuân thủ theo Restful action sẽ trả dữ liệu ra dưới dạng JSON.
2.3 Xây dựng client-side
Khởi tạo
- Như đã trình bày ở phần đầu, AngularJS tạo ra một mô hình MVC thu nhỏ trên client-side và tất cả đều được định nghĩa bên trong folder: app/assets/javascripts/angular/. Do đó ta cần phải tạo sub-folder dành cho AngularJS trong project:
$ mkdir -p app/assets/javascripts/angular/controllers app/assets/javascripts/angular/directives app/assets/javascripts/angular/services
- Bên cạnh đó, ta cần phải thêm vào thư viện của AngularJS. Về cơ bản, thư viên Angular có thể thêm bằng sử dụng gem angular hoặc sử dụng CDN. Ở trong phần này, chúng ta sẽ thêm AngularJS library vào trong project sử dụng CDN của Google:
<!DOCTYPE html> <html> <head> <title>AngularjsApp</title> <%= stylesheet_link_tag 'application', media: 'all'%> <%= csrf_meta_tags %> </head> <body> <header> Angular Casts </header> <%= yield %> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular-resource.min.js"></script> <%= javascript_include_tag 'application'%> </body> </html>
-
Tiếp đến, ta khởi tạo Angular App bằng một file js.coffee và thêm vào trong file application.js:
app/assets/javascripts/app.js.coffee:
window.App = angular.module("AngularCasts", ["ngResource"])
app/assets/javascripts/application.js:
//= require app //= require_tree ./angular
Tạo home page
- Tạo ra một controller và định nghĩa root dành cho home page:
$ rails g controller home index
config/routes.rb:
Rails.application.routes.draw do scope :api do get "/screencasts(.:format)" => "screencasts#index" get "/screencasts/:id(.:format)" => "screencasts#show" end root to: "home#index" end
Từ đây trở đi là Angular !
-
Thêm vào view:
app/views/layouts/application.html.erb:
<!DOCTYPE html> <html ng-app="AngularCasts"> ...... <body> <header> Angular Casts </header> .....
- Khởi tạo Controller dành cho AngularJS: app/assets/javascripts/angular/controllers/screencasts_ctrl.js.coffee:
App.controller "ScreencastsCtrl", ["$scope", "Screencast", ($scope, Screencast) -> $scope.message = "Angular Hello World! ]
-
Hiển thị message trên home page:
app/views/home/index.html.erb:
<div ng-controller="ScreencastsCtrl"> <h1>Message: {{message}}</h1> </div>
=> truy cập thử http://localhost:3000 để kiểm tra message !
- Thêm một chút CSS (cũng không ít lắm