11/08/2018, 22:47

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 ...

angular_rr.jpg

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             </div>
            
            <div class=
0