AngularJS के साथ शुरुआत करना कठिन नहीं है। दस्तावेज़ीकरण वहाँ से कुछ बेहतरीन है और इसके ट्यूटोरियल काफी सरल हैं।
लेकिन जब आप तकनीकों का संयोजन शुरू करते हैं तो चीजें मुश्किल हो जाती हैं।
यदि आप सीधे जावास्क्रिप्ट के बजाय कॉफीस्क्रिप्ट का उपयोग कर रहे हैं, तो आप जानते हैं कि प्रीप्रोसेसिंग चिंताओं को ध्यान में रखना है - साथ ही स्पष्ट वाक्यविन्यास अंतर भी। ये अपने आप में मामूली मुद्दे हैं, लेकिन क्या होगा यदि आप रूबी ऑन रेल्स, जैस्मीन और कर्मा को मिक्स में फेंक दें? यह आश्चर्यजनक रूप से पेचीदा हो जाता है।
यह ठीक वही स्टैक है जिसका उपयोग हम इस ट्यूटोरियल में करने जा रहे हैं। इसलिए नहीं कि हम सज़ा के भूखे हैं, बल्कि क्योंकि इस तरह का सेटअप आप वास्तविक दुनिया में देखेंगे।
यह ट्यूटोरियल मानता है कि आप रेल के साथ सहज हैं, लेकिन जरूरी नहीं कि एंगुलरजेएस।
बेस रेल ऐप बनाना
चूंकि इसमें बहुत सारी तकनीकी परतें शामिल हैं, इसलिए मैं एक साधारण एप्लिकेशन बनाने जा रहा हूं जो मुश्किल से कुछ भी करता है। हम रेस्तरां के लिए सीआरयूडी कार्यक्षमता स्थापित करेंगे - वास्तव में, केवल सीआर भाग। -यूडी को पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।;-)
हम एप्लिकेशन को रेस्टोरेंटर . कहेंगे ।
मैं यहां पोस्टग्रेएसक्यूएल और आरएसपीईसी का उपयोग कर रहा हूं, लेकिन डीबीएमएस और सर्वर-साइड टेस्टिंग फ्रेमवर्क महत्वपूर्ण नहीं हैं। आप जो चाहें उपयोग कर सकते हैं।
आरंभिक सेटअप
पहले प्रोजेक्ट बनाएं:
$ rails new restauranteur --database=postgresql --skip-test-unit
यदि आप पाउ का उपयोग कर रहे हैं, तो अपने प्रोजेक्ट को पॉव में जोड़ें:
$ ln -s /Users/jasonswett/projects/restauranteur ~/.pow/restauranteur
PostgreSQL डेटाबेस उपयोगकर्ता बनाएँ:
$ createuser -P -s -e restauranteur
अपने Gemfile में RSpec जोड़ें:
# Gemfile
gem "rspec-rails", "~> 2.14.0"
आरएसपीईसी स्थापित करें:
$ bundle install
$ rails g rspec:install
डेटाबेस बनाएं:
$ rake db:create
रेस्तरां मॉडल बनाना
अब जब हमने अपना प्रोजेक्ट और डेटाबेस बना लिया है, तो चलिए अपना पहला संसाधन बनाते हैं। रेस्तरां संसाधन में केवल एक विशेषता होगी:नाम , जो एक स्ट्रिंग है।
$ rails generate scaffold restaurant name:string
अब, इसके बारे में ओसीडी होने के लिए, हम सुनिश्चित करेंगे कि रेस्तरां के नाम अद्वितीय हों।
# 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 को मिश्रण में लाना
एक बार में आप पर सब कुछ डंप करने के बजाय, मैं पहले एंगुलरजेएस-रेल एप्लिकेशन का सबसे सरल "हैलो, वर्ल्ड" संस्करण प्रदर्शित करना चाहता हूं और फिर उस पर हमारे रेस्तरां सीआरयूडी कार्यक्षमता का निर्माण करना चाहता हूं।
कोई कारण नहीं है कि हमारा "हैलो, वर्ल्ड" पेज किसी विशेष रेल संसाधन से जुड़ा होना चाहिए या होना चाहिए। इस कारण से, हम एक StaticPagesController
बनाएंगे हमारे AngularJS होम पेज की सेवा के लिए।
नियंत्रक बनाएं
$ rails generate controller static_pages index
अभी हमारा रूट रूट "वेलकम टू रेल्स" पेज है। आइए इसे index
पर सेट करें हमारे नए StaticPagesController
. की कार्रवाई :
# config/routes.rb
Restauranteur::Application.routes.draw do
# Add the following line
root 'static_pages#index'
end
कोणीय डाउनलोड करें
- अपने परीक्षणों को बाद में ठीक से काम करने के लिए, हमें
angular-mocks.js
नामक एक फ़ाइल की आवश्यकता होगी . मुझे नहीं लगता कि एंगुलर डॉक्स में कहीं भी इसका कोई उल्लेख है, लेकिन यह आवश्यक है। - 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 फ़ाइल की आवश्यकता के बारे में बताना चाहते हैं, और हम यह सुनिश्चित करना चाहते हैं कि यह उस पर निर्भर अन्य फ़ाइलों से पहले लोड हो जाए। (हम इन निर्भरताओं को प्रबंधित करने के लिए RequJS जैसे कुछ का उपयोग कर सकते हैं, और शायद यही वह है जो मैं उत्पादन उत्पाद पर करूँगा, लेकिन इस ट्यूटोरियल के प्रयोजनों के लिए मैं जितना संभव हो सके प्रौद्योगिकी स्टैक को पतला रखना चाहता हूं।)
नोट: कोणीय और टर्बोलिंक एक दूसरे के साथ संघर्ष कर सकते हैं, इसलिए हम उन्हें यहां अक्षम कर देते हैं
// 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 .
लेआउट सेट करें
हम एनजी-ऐप और एनजी-व्यू जोड़ेंगे, जो संकेत देते हैं कि हमारे पेज में एक एंगुलर ऐप है। यह भी ध्यान दें कि Turbolinks के उल्लेख हटा दिए गए हैं।
<%= yield %>
एक कोणीय नियंत्रक बनाना
पहले हमारे नियंत्रकों के लिए एक निर्देशिका बनाते हैं। आप इसे जो चाहें नाम दे सकते हैं।
$ mkdir -p app/assets/javascripts/angular/controllers
अब कंट्रोलर फाइल को ही बनाते हैं। मैं इस कंट्रोलर को "होम कंट्रोलर" कह रहा हूं और एंगुलर में कन्वेंशन आपके कंट्रोलर फाइलनाम को 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'
})
])
एक कोणीय टेम्प्लेट जोड़ें
हम अपने एंगुलर टेम्प्लेट को रखने के लिए एक जगह भी चाहते हैं। मैंने अपना public/templates
में डालने का निर्णय लिया . दोबारा, आप उन्हें जहां चाहें वहां रख सकते हैं।
mkdir public/templates
अगर हम एक फ़ाइल बनाते हैं public/templates/home.html
कुछ मनमानी सामग्री के साथ, हमें इसे ब्राउज़र में देखने में सक्षम होना चाहिए।
This is the home page.
अब, यदि आप https://restauranteur.dev/
. पर जाते हैं (या https://localhost:3000/
यदि आप पाउ का उपयोग नहीं कर रहे हैं) और आपको 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"
एक रेल नियंत्रक में। हम प्लग कर सकते हैंfoo
इस तरह से डबल-ब्रेस सिंटैक्स का उपयोग करके टेम्पलेट में:
Value of "foo": {{foo}}
इस बार वास्तविक रूप से करना
हमने पहले ही एक सरल हैलो वर्ल्ड ऐप बना लिया है। एक पूर्ण विकसित सीआरयूडी एप्लिकेशन बनाना ज्यादा कठिन नहीं है।
डेटाबेस को सीड करें
यदि हम डेटाबेस में कुछ रेस्तरां के साथ शुरुआत करते हैं तो हमारे रेस्तरां सीआरयूडी के साथ काम करना थोड़ा अधिक सार्थक होगा। यहां एक बीज फ़ाइल है जिसका आप उपयोग कर सकते हैं।
# 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'
]
});
};
कर्म स्थापित करें और सर्वर शुरू करें:
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
बदलें। toexpect(scope.restaurants.length).toBe 1
और फिर से परीक्षण चलाएँ।
इस परीक्षण की सार्थकता जो हमने अभी जोड़ी है, स्पष्ट रूप से संदिग्ध है, लेकिन मेरा इरादा यहां आपको यह पता लगाने के काम को बचाने के लिए है कि अपने एंगुलर कोड को टेस्ट हार्नेस में कैसे लाया जाए। कुछ चीजें हैं, जैसे कि CoffeeScript प्रीप्रोसेसर औरangular-mocks.js
समावेशन जो पूरी तरह से स्पष्ट नहीं हैं और मुझे ठीक होने में कई घंटे लग गए।
रेस्तरां बनाना पृष्ठ
आइए अब अपने रेस्टोरेंट इंडेक्स टेम्प्लेट में एक अस्थायी समायोजन करें:
* {{restaurant.name}} ({{restaurant.id}})
अगर आप अब /#/restaurants
पर फिर से जाते हैं , आप देखेंगे कि किसी भी रेस्तरां के पास अपनी आईडी नहीं है। वे खाली क्यों हैं?
जब आप रेल 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
को ताज़ा करते हैं , आपको आईडी दिखाई देनी चाहिए।
आइए अब टेम्प्लेट को वापस उसी तरह बदलते हैं जैसे वह मूल रूप से था:
[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}"
]
रेल में सम्मेलन यह है कि 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 को रेल 4 में प्लग करने में कुछ समय बचा लिया है। इसके बाद मैं inngResource देखने की सिफारिश कर सकता हूं, जो CRUD की कार्यक्षमता को और अधिक शुष्क बनाने में मदद कर सकता है।
अधिक सीखने में रुचि रखते हैं?
एडम एंडरसन की महान पोस्ट देखें, जिसकी रेल 4.0 श्रृंखला में एंगुलरजेएस ऐप को बूटस्ट्रैप करने से मुझे एंगुलरजेएस और रेल के साथ शुरुआत करने में मदद मिली। आप उनके ट्यूटोरियल को भी पढ़ना पसंद कर सकते हैं, लेकिन यह ट्यूटोरियल इस मायने में अलग है कि मैं आपको सभी विवरणों को _वास्तव में_चम्मच-फीड करने की कोशिश करता हूं, जिससे आपके मातम में फंसने की संभावना कम हो जाती है।