12/08/2018, 13:46

Install Angular and Bootstrap in Rails

Bài viết này mình xin giới thiệu về cách cài đặt, sử dụng angular và bootstrap trong rails Việc đầu tiên bạn phải tạo ra 1 app của rails bằng lệnh rails new example Vào thư mục Gemfile liệt kê các gem cần thiết, nhớ bỏ gem turbolinks ra khỏi Gemfile gem 'sass' , '3.2.19' group ...

Bài viết này mình xin giới thiệu về cách cài đặt, sử dụng angular và bootstrap trong rails

Việc đầu tiên bạn phải tạo ra 1 app của rails bằng lệnh

rails new example

Vào thư mục Gemfile liệt kê các gem cần thiết, nhớ bỏ gem turbolinks ra khỏi Gemfile

gem 'sass', '3.2.19'
group :test, :development do
  gem "rspec-rails", "~> 2.0"
  gem "factory_girl_rails", "~> 4.0"
  gem "capybara"
  gem "database_cleaner"
  gem "selenium-webdriver"
end

Lưu ý: Bạn phải cài 2 gem capybara và selenium-webdriver này để test và bạn phải cài firefox làm môi trường test

Các câu lệnh sau để cài đặt và chạy chương trình bundle install

rake db:create

rails s

Front-end phụ thuộc vào quản lý của Bower

Bởi vì rails không cung cấp bất kỳ cách quản lý font-end asset nào. Không giống như các thư viện javascript, font hoặc css được cộng đồng phát triển đã mang đến những package phổ biến trong RubyGem.

Chúng ta sẽ không dựa vào RubyGem của asset. Thay vào đó, chúng ta sẽ sử dụng Bower để quản lý. Bower được tạo bởi Twitter để quản lý font-end asset và hầu hết các thư viện, bao gồm cả module Angular.

Để cài được bower bạn cần chạy lệnh sau npm install -g bower

Bây giờ thì bower đã được cài đặt, chúng ta cần cài thêm gem bower-rails, gem này sẽ là cầu nối giao tiếp của ứng dụng Rails và Bower (thêm gem này vào Gemfile)

Bower làm việc tương tự Bundler. Tiếp theo bạn chạy lệnh rake -T bower trên console

> rake -T bower
rake bower:cache:clean                   # Clear the bower cache ('bower cache clean')
rake bower:clean                         # Attempt to keep only files listed in 'main' of each component's bower.json
rake bower:install[options]              # Install components from bower
rake bower:install:deployment[options]   # Install components from bower using previously generated bower.json
rake bower:install:development[options]  # Install both dependencies and devDependencies from bower
rake bower:install:production[options]   # Install only dependencies, excluding devDependencies from bower
rake bower:list                          # List bower components
rake bower:resolve                       # Resolve assets paths in bower components
rake bower:update[options]               # Update bower components
rake bower:update:prune[options]         # Update existing components and uninstalls extraneous components

Bower có file Bowerfile tương tự như Gemfile. Đầu tiên bạn phải cài Boostrap, Boostrap là không bắt buộc, nhưng trong những ứng dụng demo này chúng ta phải sử dụng để xây dựng giao diện. Bạn thêm vào file Bowerfile hai dòng sau để có thể sử dụng được boostrap:

asset 'angular'

asset 'bootstrap-sass-official'

Và bây giờ bạn cài đặt thông qua rake task bower:install

> rake bower:install
bower.js files generated
/usr/local/share/npm/bin/bower install
bower bootstrap-sass-official#*       not-cached git://github.com/twbs/bootstrap-sass.git#*
bower bootstrap-sass-official#*          resolve git://github.com/twbs/bootstrap-sass.git#*
bower angular#*                           cached git://github.com/angular/bower-angular.git#1.2.13
bower angular#*                         validate 1.2.13 against git://github.com/angular/bower-angular.git#*
bower bootstrap-sass-official#*         download https://github.com/twbs/bootstrap-sass/archive/v3.1.1.tar.gz
bower angular#*                              new version for git://github.com/angular/bower-angular.git#*
bower angular#*                          resolve git://github.com/angular/bower-angular.git#*
bower angular#*                         download https://github.com/angular/bower-angular/archive/v1.2.14.tar.gz
bower bootstrap-sass-official#*          extract archive.tar.gz
bower angular#*                          extract archive.tar.gz
bower bootstrap-sass-official#*         resolved git://github.com/twbs/bootstrap-sass.git#3.1.1
bower angular#*                         resolved git://github.com/angular/bower-angular.git#1.2.14
bower bootstrap-sass-official#*          install bootstrap-sass-official#3.1.1
bower angular#*                          install angular#1.2.14

bootstrap-sass-official#3.1.1 bower_components/bootstrap-sass-official

angular#1.2.14 bower_components/angular

Bower được cài đặt phụ thuộc vào thư mục vendor/assets/bower_components. Trông thư mục này có vẻ khá lạ lẫm nhưng nó cho phép bạn tách các thư viện được quản lý bởi Bower thành 3 phần

Trong phần cấu hình, bạn thêm vào file config/application.rb các dòng sau

config.assets.paths <<
Rails.root.join("vendor","assets","bower_components")

config.assets.paths << Rails.root.join("vendor","assets","bower_components",
"bootstrap-sass-official","assets","fonts")

config.assets.precompile << %r(.*.(?:eot|svg|ttf|woff|woff2)$)

Trong file app/assets/javascripts/application.js bạn thêm vào dòng sau

//= require angular/angular

và bỏ đi

//= require turbolinks

Trong file app/assets/stylesheets/application.css.scss bạn thêm vào 2 dòng sau

@import "bootstrap-sass-official/assets/stylesheets/bootstrap-sprockets";

@import "bootstrap-sass-official/assets/stylesheets/bootstrap";

Chạy ứng dụng cùng với Angular

1. Xử lý thẻ input

Vậy là chúng đã cài đặt xong môi trường, bây giờ chúng ta sẽ chạy ứng dụng nhỏ đầu tiên

Bạn tạo ra file controller là home_controller

class HomeController < ApplicationController
  def index
  end
end

Trên file app/views/home/index.html.erb bạn thêm vào trong file

<div class="container-fluid" ng-app="receta">
  <div class="panel panel-success">
    <div class="panel-heading">
      <h1 ng-if="name">Hello, {{name}}</h1>
    </div>
    <div class="panel-body">
      <form class="form-inline">
        <div class="form-group">
          <input class="form-control" type="text" placeholder="Enter your name" autofocus ng-model="name">
        </div>
      </form>
    </div>
  </div>
</div>

Cuối cùng là bạn tạo ra file app.coffee thêm vào trong file

receta = angular.module('receta',[
])

Và bây giờ bạn có thể chạy ứng dụng của mình rồi đấy, kết quả khi chạy ứng dụng là với bất kỳ thứ gì bạn điền vào thẻ input thì đều hiển thị ngay lên luôn màn hình mà ko cần bất kỳ nút click nào

2. Ứng dụng tìm kiếm trên Angular

Để làm được ứng dụng này chúng ta phải trải qua hai bước sau

a. Tạo ra giao diện tìm kiếm cơ bản trên view

Tạo ra file app/assets/javascripts/app.coffee.erb, app.coffee có quyền truy cập đến asset_path helper

app.config([ '$routeProvider',
  ($routeProvider)->
    $routeProvider
      .when('/',
        templateUrl: "<%= asset_path('index.html') %>"
        controller: 'SomeController'
      )
      .when('/recipes/new',
        templateUrl: "<%= asset_path('new.html') %>"
        controller: 'SomeOtherController'
      )
])

Để chạy được ứng dụng này bạn cần phải cài thêm Gemfile angular-rails-templates và thêm vào Bowerfile angular-route. Sau khi cài đặt thành công bạn thêm vào trong file /app/assets/javascripts/application.js 2 dòng sau:

//= require angular-route/angular-route

//= require angular-rails-templates

Trên file app/views/home/index.html.erb bạn thêm vào

<div ng-app="receta">
  <div class="view-container">
    <div ng-view class="view-frame animate-view"></div>
  </div>
</div>

Sử dụng ng-app để nói với Angular biết rằng ứng dụng cần được load và ng-view để chỉ ra nơi mà view có thể được render tới. Trong thẻ div view-container có chứa 2 class view-frame và animate-view để tạo ra những hình ảnh động nếu muốn, nhưng tạm thời chúng ta chưa cần quan tâm đến điều này.

Tiếp theo chúng ta cần cài đặt ứng dụng receta của Angular để có thể render view. Từ bây giờ chúng ta cần module angular-routes được cung cấp bởi angular-rails-templates đã được cài trong Gemfile.

Tạo ra file app/assets/javascripts/app.coffee

receta = angular.module('receta',[
  'templates',
  'ngRoute',
  'controllers',
])

receta.config([ '$routeProvider',
  ($routeProvider)->
    $routeProvider
      .when('/',
        templateUrl: "index.html"
        controller: 'RecipesController'
      )
])

controllers = angular.module('controllers',[])
controllers.controller("RecipesController", [ '$scope',
  ($scope)->
])

Và việc cuối cùng trong phần tạo giao diện này là tạo ra file index.htm, file này sẽ được đặt trong thư mục mặc định là app/assets/javascripts/templates được tạo ra bởi gem angular-rails-templates

<header class="row">
  <h1 class="text-center col-md-6 col-md-offset-3">Find Recipes</h1>
</header>
<section class="row">
  <form>
    <div class="form-group col-md-6 col-md-offset-3">
      <label for="keywords" class="sr-only">Keywords</label>
      <input ng-model="keywords" name="keywords" type="text" autofocus class="form-control" placeholder="Recipe name, e.g. Baked Potato">
    </div>
    <div class="form-group col-md-6 col-md-offset-3 text-center">
      <button ng-click="search(keywords)" class="btn btn-primary btn-lg">Search</button>
    </div>
  </form>
</section>
<hr>
<section class="row" ng-if="recipes">
  <h1 class="text-center h2">Results</h1>
   <ul class="list-unstyled">
    <li ng-repeat="recipe in recipes">
      <section class="well col-md-6 col-md-offset-3">
        <h1 class="h3 col-md-6 text-right" style="margin-top: 0"><a href="#">{{recipe.name}}</a></h1>
        <div class="col-md-6">
          <button class="btn btn-info">Edit</button>
          <button class="btn btn-danger">Delete</button>
        </div>
      </section>
    </li>
  </ul>
</section>

Chúng ta sử dụng ng-if để ẩn hoàn toàn kết quả nếu không có thứ gì trả về

Và giao diện sau khi tạo xong sẽ trông như thế này

SearchUI.png

b.Phần controller xử lý tìm kiếm

Tại file app/assets/javascripts/app.coffee

receta = angular.module('receta',[
  'templates',
  'ngRoute',
  'controllers',
])

receta.config([ '$routeProvider',
  ($routeProvider)->
    $routeProvider
      .when('/',
        templateUrl: "index.html"
        controller: 'RecipesController'
      )
])

recipes = [
  {
    id: 1
    name: 'Baked Potato w/ Cheese'
  },
  {
    id: 2
    name: 'Garlic Mashed Potatoes',
  },
  {
    id: 3
    name: 'Potatoes Au Gratin',
  },
  {
    id: 4
    name: 'Baked Brussel Sprouts',
  },
]
controllers = angular.module('controllers',[])
controllers.controller("RecipesController", [ '$scope', '$routeParams', '$location',
  ($scope,$routeParams,$location)->
    $scope.search = (keywords)->  $location.path("/").search('keywords',keywords)

    if $routeParams.keywords
      keywords = $routeParams.keywords.toLowerCase()
      $scope.recipes = recipes.filter (recipe)-> recipe.name.toLowerCase().indexOf(keywords) != -1
    else
      $scope.recipes = []
])

Vậy là chúng ta đã xây dựng xong ứng dụng tìm kiếm trên Angular

0