Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

AngularJSとRails4の使用を開始する

AngularJSの使用を開始するのは難しくありません。ドキュメントはそこにある最高のもののいくつかであり、チュートリアルは十分に単純です。

しかし、テクノロジーを組み合わせ始めると、物事はトリッキーになります。

ストレートJavaScriptの代わりにCoffeeScriptを使用している場合は、前処理の問題と、明らかな構文の違いを考慮に入れる必要があることをご存知でしょう。これらはそれ自体は小さな問題ですが、Ruby on Rails、Jasmine、Karmaを組み合わせて使用​​するとどうなりますか?驚くほどトリッキーになります。

これはまさに、このチュートリアルで使用するスタックです。私たちが罰の無駄遣いであるからではなく、これは現実の世界で見られるような設定だからです。

このチュートリアルは、Railsに慣れていることを前提としていますが、必ずしもAngularJSである必要はありません。

ベースRailsアプリの作成

非常に多くのテクノロジーレイヤーが関係しているので、ほとんど何もしない単純なアプリケーションを作成します。レストラン用にCRUD機能を設定します。実際にはCR部分だけです。 -UDは、読者の練習問題として残されています。;-)

このアプリケーションをレストラン経営者と呼びます 。

ここではPostgreSQLとRSpecを使用していますが、DBMSとサーバー側のテストフレームワークは重要ではありません。好きなものを使うことができます。

初期設定

最初にプロジェクトを作成します:

$ rails new restauranteur --database=postgresql --skip-test-unit

Powを使用している場合は、プロジェクトをPowに追加します:

$ ln -s /Users/jasonswett/projects/restauranteur ~/.pow/restauranteur

PostgreSQLデータベースユーザーを作成します:

$ createuser -P -s -e restauranteur

RSpecをGemfileに追加します:

# Gemfile
gem "rspec-rails", "~> 2.14.0"

RSpecのインストール:

$ bundle install
$ rails g rspec:install

データベースを作成します:

$ rake db:create
レストランモデルの作成

プロジェクトとデータベースが作成されたので、最初のリソースを作成しましょう。レストランリソースには、名前という1つの属性のみがあります。 、これは文字列です。

$ rails generate scaffold restaurant name:string

さて、それについてのOCDであるために、レストラン名が一意であることを確認します。

# db/migrate/[timestamp]_create_restaurants.rb

class CreateRestaurants < ActiveRecord::Migration
  def change
    create_table :restaurants do |t|
      t.string :name

      t.timestamps
    end

    # Add the following line
    add_index :restaurants, :name, unique: true
  end
end

移行を実行します:

$ rake db:migrate

無効なレストランを作成できないことを確認するために、いくつかの仕様を追加しましょう。固有障害が生のエラーをもたらすことに注意してください。

require 'spec_helper'

describe Restaurant do
  before do
    @restaurant = Restaurant.new(name: "Momofuku")
  end

  subject { @restaurant }

  it { should respond_to(:name) }
  it { should be_valid }

  describe "when name is not present" do
    before { @restaurant.name = " " }
    it { should_not be_valid }
  end

  describe "when name is already taken" do
    before do
      restaurant_with_same_name = @restaurant.dup
      restaurant_with_same_name.name = @restaurant.name.upcase
      restaurant_with_same_name.save
    end

    it { should_not be_valid }
  end
end

これらのバリデーターを追加すると、仕様に合格します:

class Restaurant < ActiveRecord::Base 
  validates :name, presence: true, uniqueness: { case_sensitive: false }
end

これで先に進むことができます。

AngularJSをミックスに取り入れます

すべてを一度にダンプするのではなく、まずAngularJS-Railsアプリケーションの最も単純な「Hello、world」バージョンをデモンストレーションしてから、レストランのCRUD機能をその上に構築したいと思います。

「Hello、world」ページを特定のRailsリソースに関連付ける必要がある、または関連付ける必要がある理由はありません。このため、StaticPagesControllerを作成します AngularJSホームページを提供します。

コントローラーを作成する
$ rails generate controller static_pages index

現在のルートルートは、「WelcometoRails」ページです。 indexに設定しましょう 新しいStaticPagesControllerのアクション :

# config/routes.rb

Restauranteur::Application.routes.draw do
  # Add the following line
  root 'static_pages#index'
end
Angularをダウンロード
  1. 後でテストを正しく機能させるには、angular-mocks.jsというファイルが必要です。 。 Angularのドキュメントにはこれについての言及はどこにもないと思いますが、必要です。
  2. AngularJSチュートリアルでは、ドキュメントに最新の最先端バージョンがリストされていますが、正しく思い出せば、angular.js間の互換性に問題がありました。 およびangular-mocks.js 最新バージョンの場合。バージョン1.1.5が連携して動作したことはわかっているので、これは最新の安定バージョンではありませんが、ここにリストしているバージョンです。もちろん、時間が経つにつれて、互換性の状況はおそらく改善されるでしょう。

angular.jsをダウンロードする およびangular-mocks.js code.angularjs.orgから、ファイルをapp/assets/javascriptsに移動します 。

$ wget https://code.angularjs.org/1.1.5/angular.js \
https://code.angularjs.org/1.1.5/angular-mocks.js
$ mv angular* app/assets/javascripts
アセットパイプラインに追加

次に、アプリケーションにAngularJSファイルを要求するように指示し、それに依存する他のファイルよりも先にファイルが読み込まれるようにします。 (これらの依存関係を管理するためにRequireJSのようなものを使用できます。これはおそらく本番製品で行うことですが、このチュートリアルの目的のために、テクノロジースタックを可能な限り薄くしたいと思います。)

注: AngularとTurbolinkは互いに競合する可能性があるため、ここでは無効にします

// app/assets/javascripts/application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs

// Add the following two lines
//= require angular
//= require main

//= require_tree .
レイアウトを設定する

ng-appとng-viewを追加します。これらは、ページにAngularアプリがあることを示します。また、ターボリンクの言及が削除されていることにも注意してください。

  <%= yield %>
Angularコントローラーの作成

まず、コントローラー用のディレクトリを作成しましょう。好きな名前を付けることができます。

$ mkdir -p app/assets/javascripts/angular/controllers

それでは、コントローラーファイル自体を作成しましょう。私はこのコントローラーを「ホームコントローラー」と呼んでいます。Angularの規則では、コントローラーのファイル名にCtrlを追加します。 。したがって、ファイル名はapp/assets/javascripts/angular/controllers/HomeCtrl.js.coffeeになります。 :

# app/assets/javascripts/angular/controllers/HomeCtrl.js.coffee

@restauranteur.controller 'HomeCtrl', ['$scope', ($scope) ->
  # Notice how this controller body is empty
]
角度ルートを追加

次に、HomeCtrlを作成するために、ルーティングディレクティブを追加します。 「デフォルトページ」になります。ここでは、app/assets/javascripts/main.js.coffeeでルーティングを定義しています。 、しかし、ファイル名は重要ではないと思います。

# app/assets/javascripts/main.js.coffee

# This line is related to our Angular app, not to our
# HomeCtrl specifically. This is basically how we tell
# Angular about the existence of our application.
@restauranteur = angular.module('restauranteur', [])

# This routing directive tells Angular about the default
# route for our application. The term "otherwise" here
# might seem somewhat awkward, but it will make more
# sense as we add more routes to our application.
@restauranteur.config(['$routeProvider', ($routeProvider) ->
  $routeProvider.
    otherwise({
      templateUrl: '../templates/home.html',
      controller: 'HomeCtrl'
    }) 
])
Angularテンプレートを追加する

また、Angularテンプレートを保持する場所も必要です。 public/templatesに入れることにしました 。繰り返しになりますが、好きな場所に配置できます。

mkdir public/templates

ファイルを作成する場合public/templates/home.html 任意のコンテンツがあれば、ブラウザで表示できるはずです。


This is the home page.

ここで、https://restauranteur.dev/にアクセスすると (またはhttps://localhost:3000/ Powを使用していない場合)、home.htmlの内容が表示されます。 。

データバインディングの例

それは種類です 興味深いですが、おそらくあまり印象的ではありません。実際にネットワークを介して何かを送信してみましょう。 app/assets/angular/controllers/HomeCtrl.js.coffeeを編集します このように:

# app/assets/angular/controllers/HomeCtrl.js.coffee 

@restauranteur.controller 'HomeCtrl', ['$scope', ($scope) -> 
  $scope.foo = 'bar'
]

これは、@foo = "bar"と言うのと似ています。 Railsコントローラーで。 fooをプラグインできます 次のような二重中括弧構文を使用して、テンプレートに追加します。

Value of "foo": {{foo}}  
今回は実際にやっています

簡単なHelloWorldアプリを既に作成しました。本格的なCRUDアプリケーションの作成はそれほど難しくありません。

データベースのシード

データベース内のいくつかのレストランから始めると、レストランCRUDでの作業はもう少し意味があります。使用できるシードファイルは次のとおりです。

# db/seeds.rb

Restaurant.create([
  { name: "The French Laundry" },
  { name: "Chez Panisse" },
  { name: "Bouchon" },
  { name: "Noma" },
  { name: "Taco Bell" },
])
rake db:seed
レストランのインデックスページを作成する

まず、レストランのテンプレートフォルダを作成しましょう:

mkdir public/templates/restaurants

作成する最初のテンプレートはインデックスページです:

[index](/#)

  * {{ restaurant.name }}

これらの意味については、すぐに説明します。まず、コントローラーを作成しましょう:

# app/assets/javascripts/angular/controllers/RestaurantIndexCtrl.js.coffee

@restauranteur.controller 'RestaurantIndexCtrl', ['$scope', '$location', '$http', ($scope, $location, $http) ->
  $scope.restaurants = []
  $http.get('./restaurants.json').success((data) ->
    $scope.restaurants = data
  )
]

最後に、ルーティング構成を調整します:

# app/assets/javascripts/main.js.coffee

@restauranteur = angular.module('restauranteur', [])

@restauranteur.config(['$routeProvider', ($routeProvider) ->
  $routeProvider.
    when('/restaurants', {
      templateUrl: '../templates/restaurants/index.html',
      controller: 'RestaurantIndexCtrl'
    }).
    otherwise({
      templateUrl: '../templates/home.html',
      controller: 'HomeCtrl'
    })
])

これで、最後に、URI /#/restaurantsに移動できます。 そして、レストランのリストを見ることができるはずです。先に進む前に、テストを追加しましょう。

最初のテストを追加する

JSテストフォルダーを追加します:

mkdir spec/javascripts

テストを書く:

# spec/javascripts/controllers_spec.js.coffee

describe "Restauranteur controllers", ->
  beforeEach module("restauranteur")

  describe "RestaurantIndexCtrl", ->
    it "should set restaurants to an empty array", inject(($controller) ->
      scope = {}
      ctrl = $controller("RestaurantIndexCtrl",
        $scope: scope
      )
      expect(scope.restaurants.length).toBe 0
    )

構成の追加:

// spec/javascripts/restauranteur.conf.js

module.exports = function(config) {
  config.set({
    basePath: '../..',

    frameworks: ['jasmine'],

    autoWatch: true,

    preprocessors: {
      '**/*.coffee': 'coffee'
    }, 

    files: [
      'app/assets/javascripts/angular.js',
      'app/assets/javascripts/angular-mocks.js',
      'app/assets/javascripts/main.js.coffee',
      'app/assets/javascripts/angular/controllers/RestaurantIndexCtrl.js.coffee',
      'app/assets/javascripts/angular/*',
      'spec/javascripts/*_spec.js.coffee'
    ]  
  });
};

Karmaをインストールし、サーバーを起動します:

sudo npm install -g karma
sudo npm install -g karma-ng-scenario
karma start spec/javascripts/restauranteur.conf.js

https://localhost:9876/にアクセスした場合 、テストが実行され、成功します。テストが失敗することを確認したい場合は、expect(scope.restaurants.length).toBe 0を変更してください。 to expect(scope.restaurants.length).toBe 1 もう一度テストを実行します。

追加したこのテストの意味は明らかに疑わしいですが、ここでの私の意図は、Angularコードをテストハーネスに取り込む方法を理解する手間を省くことです。 CoffeeScriptプリプロセッサやangular-mocks.jsなどの特定のものがあります 完全に明白ではなく、正しく理解するために頭を悩ませるのに数時間かかった包含。

レストランページの構築

次に、レストランのインデックステンプレートを一時的に調整しましょう:

  * {{restaurant.name}} ({{restaurant.id}})

ここで/#/restaurantsに再度アクセスした場合 、どのレストランにもIDがないことに気付くでしょう。なぜ空白なのですか?

Rails 4でスキャフォールディングを生成すると、.jbuilderが得られます。 ファイル:

$ ls -1 app/views/restaurants/*.jbuilder
app/views/restaurants/index.json.jbuilder
app/views/restaurants/show.json.jbuilder

app/views/restaurants/index.json.jbuilderを開いた場合 、これが表示されます:

# app/views/restaurants/index.json.jbuilder

json.array!(@restaurants) do |restaurant|
  json.extract! restaurant, :name
  json.url restaurant_url(restaurant, format: :json)
end

ご覧のとおり、:nameが含まれています ただし、:idではありません 。追加しましょう:

# app/views/restaurants/index.json.jbuilder

json.array!(@restaurants) do |restaurant|
  json.extract! restaurant, :id, :name
  json.url restaurant_url(restaurant, format: :json)
end

ファイルを保存して/#/restaurantsを更新した場合 、IDが表示されるはずです。

次に、テンプレートを元の状態に戻します。

[index](/#)

  * {{ restaurant.name }}

ある時点で、これらをviewRestaurant()と呼ばれるものに向けていることに気付いたかもしれません。 しかし、実際にはviewRestaurant()と呼ばれるものを定義したことはありません。 。今すぐやってみましょう:

# app/assets/javascripts/angular/controllers/RestaurantIndexCtrl.js.coffee

@restauranteur.controller 'RestaurantIndexCtrl', ['$scope', '$location', '$http', ($scope, $location, $http) ->
  $scope.restaurants = []
  $http.get('./restaurants.json').success((data) ->
    $scope.restaurants = data
  )

  # Add the following lines
  $scope.viewRestaurant = (id) ->
    $location.url "/restaurants/#{id}"
]

Railsの規則では、resource_name/:id 「表示」ページにマップします。これをここで行います。ショーテンプレート、ルート、コントローラーを作成しましょう。

# {{restaurant.name}}
# app/assets/javascripts/main.js.coffee

@restauranteur = angular.module('restauranteur', [])

@restauranteur.config(['$routeProvider', ($routeProvider) ->
  $routeProvider.
    when('/restaurants', {
      templateUrl: '../templates/restaurants/index.html',
      controller: 'RestaurantIndexCtrl'
    }).
    when('/restaurants/:id', {
      templateUrl: '../templates/restaurants/show.html',
      controller: 'RestaurantShowCtrl'
    }).
    otherwise({
      templateUrl: '../templates/home.html',
      controller: 'HomeCtrl'
    })
])
# app/assets/javascripts/angular/controllers/RestaurantShowCtrl.js.coffee

@restauranteur.controller 'RestaurantShowCtrl', ['$scope', '$http', '$routeParams', ($scope, $http, $routeParams) ->
  $http.get("./restaurants/#{$routeParams.id}.json").success((data) ->
    $scope.restaurant = data
  )
]

ここで、/#/restaurantsを更新すると レストランをクリックすると、そのレストランのショーページが表示されます。イェーイ!

今のところこれですべてです

特に印象的な結果は見られなかったかもしれませんが、AngularJSをRails 4に接続する時間を節約できたと思います。次に、CRUD機能をよりドライにするのに役立つintongResourceを調べることをお勧めします。

詳細を学ぶことに興味がありますか?

Rails4.0シリーズでAngularJSアプリをブートストラップすることでAngularJSとRailsを使い始めることができたAdamAndersonのすばらしい投稿をチェックしてください。彼のチュートリアルも試してみたいと思うかもしれませんが、このチュートリアルは、雑草に巻き込まれる可能性を最小限に抑えて、すべての詳細を_really_spoon-feedしようとしているという意味で異なります。


  1. ウェブ用の Android メッセージの使用を開始する

    Google は 1 つの巨大なプラットフォームであり、疑いの余地はありません。しかし、最高の検索エンジンの 1 つであるだけでなく、日常生活を楽にするさまざまなサービスも提供しています。 Google は最近、どの Web ブラウザからでもテキスト メッセージを送受信できる Android メッセージ アプリのアップデートをリリースしました。このサービスを使用すると、Android ユーザーは任意の PC または Mac に簡単にメッセージを送信できます。 開始するには、Android メッセージ アプリの更新バージョンが必要です。それが終わったら、Web サービスで Android メッ

  2. Xen 仮想化の開始

    Zで綴られるZenは、8時間保持した後、雪の中でおしっこをしているときに頭頂部にある典型的な感覚です. Xen は X で綴られており、KVM と同様に、企業市場を対象としていますが、家庭でもビジネスでもセットアップを検討できるオープンソースの仮想化テクノロジです。 KVM に関するいくつかのチュートリアルがあり、導入記事、ストレージとネットワーク (ブリッジ ネットワークを含む) のセットアップと構成の方法、および VirtualBox との競合の解決方法をカバーしています。ここで、Xen についてもう少し学びましょう。同様に、仮想マシンをインストールして実行するために必要な最初の手順、