$resource : Create an Angular.JS app with a RESTful Rails API Pt.4

Luke Ghenco
5 min readMar 31, 2016

--

In part 1 we built a restful api using rails.

In part 2 we built up our asset pipeline to use angular, and installed bower.

In part 3 we built a basic angular app with nested routes using UI.router.

In part 4 we are going to use $resource to make our Angular app interface with our RESTful Rails API.

If you have done so, before you begin this section please make sure you have completed parts 1–3, otherwise this may not function correctly.

Step: 1 Checking our data base

Back in part 1 we created a simple database with a single note entry.

If you have not done that, please do the following command inside of your root directory of the note app.

$ rails c2.2.1 :001 > @note = Note.create(title: 'First Note', body: 'This is my first note')

This will create our first note object.

In the last lesson inside of our notes controller we have an array of objects

ctrl. notes = [ 
{
title: 'first note',
body: 'this is my first note'
},
{
title: 'second note',
body: 'this is my second note'
}
];

our first goal with resource is to now clear out this array and grab the objects from our Active Record database in our rails app.

We are currently requiring ngResource. $resource is a service used for API calls, and has CRUD built into its service. So first, please make sure that ngResource is injected into your app.js file.

angular
.module('app', ['ui.router', 'ngResource', 'templates')

We should be set up and ready to go.

Step: 2 Making a query()

The first thing we want to do is wire up our .state(‘notes’), so that we can see all of our notes stored in the database.

We first need to make a factory. Please create the following file.

app/assets/javascripts/angular-app/models/note.js

we need to use our $resource inside of this model.

# app/assets/javascripts/angular-app/models/note.jsangular 
.module('app')
.factory('Note', Note)
function Note($resource) {

var Note = $resource('http://localhost:3000/api/v1/notes/:id.json', {id: '@id'}, {
update: { method: 'PUT' }
});
return Note; }

Now that we have a Note factory we have access to several methods.

  1. get()
  2. query()
  3. save()
  4. remove()
  5. delete()

Let’s use query() in our NotesController.js

angular 
.module('app')
.controller('NotesController', NotesController);
function NotesController(Note) {

var ctrl = this;
// change our ctrl.notes = []; to query the entire Note table
ctrl.notes = Note.query();
};

Now when we load up our browser at localhost:3000/#/notes we should see the single note inside of our database.

Step: 3 new Note()

Now that we have our factory built using $resource we are able to make instances of that factory, and create new entries inside of our database.

let’s make a new controller to do this.

# app/assets/javascripts/angular-app/controller/NewNoteController.jsangular 
.module('app')
.controller('NewNoteController', NewNoteController);
function NewNoteController(Note, $location) {
// we will use $location to route back to another state
var ctrl = this; // make a new note
ctrl.note = new Note();
ctrl.addNote = function() {
ctrl.note.$save(function() {
$location.path('notes');
});
};
}

We will use the addNote() method inside of form @ new.html. You will notice the $location. This is used to direct us back to our ‘notes’ route, and we should see a new note there, but first we need to fix two things. 1 our app.js .state controller for ‘home.new’ and our home/new.html file.

# app.js......state('home.new', {
url: 'new',
templateUrl: 'home/new.html',
// use our NewNoteController, so that our form has access to it.
controller: 'NewNoteController as ctrl'
})
......

our view:

# home/new.html<h1>Add note</h1><form validate ng-submit=”ctrl.addNote()”>
<label>Title</label>
<input type=”text” ng-model=”ctrl.note.title”>
<label>Content</label>
<input type=”text” ng-model=”ctrl.note.body”>
<input type=”submit” value=”Add Note”>
</form>

with ng-submit when we click on the Add Note button we will create a new object in our database. Go ahead and load up localhost:3000/#/new and create a new entry. It should take you too the /#/notes route after you click on the Add Note button, and you should see your new note.

Step: 4 Note.get()

So we can query our entire database table and insert into our table, but how do we get a specific row from our table? We are going to ‘get()’ this.

Let’s create a new view for displaying this individual note.

app/assets/javascripts/templates/home/show.html<h3>{{ ctrl.note.title }}</h3><p>
{{ ctrl.note.body }}
</p>

We also need to add the templates to our routes and we are going to change around our routes as well please copy the following information as it has changed from our original routes.

angular
.module(‘app’, [‘ui.router’, ‘ngResource’, ‘templates’])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state(‘home’, {
url: ‘/’,
templateUrl: ‘home.html’,
controller: ‘HomeController as ctrl’
})
.state(‘home.notes’, {
url: ‘notes’,
templateUrl: ‘home/notes.html’,
controller: ‘NotesController as ctrl’
})
.state(‘home.new’, {
url: ‘new’,
templateUrl: ‘home/new.html’,
controller: ‘NewNoteController as ctrl’
})
.state(‘home.note’, {
url: ‘note/:id’,
templateUrl: ‘home/show.html’,
controller: ‘ViewNoteController as ctrl’
});

$urlRouterProvider.otherwise(‘/’);
});

Now lets update our home/notes.html

<h1>Notes</h1><ul>
<li ng-repeat=”note in ctrl.notes”>
<h3>{{ note.title }}</h3>
<p>
{{ note.body }}
</p>
<a href=”#” ui-sref=”home.note({id: note.id})”>View Note</a>
</li>
</ul>

This will give us a link to each note’s show page. We are missing one more thing though, our controller. Create this controller and add the following code.

angular
.module(‘app’)
.controller(‘ViewNoteController’, ViewNoteController);
function ViewNoteController(Note, $stateParams) {

var ctrl = this;
ctrl.note = Note.get({ id: $stateParams.id });}

Load up your browser again, and you should be able to view each individuals note view.

Step: 5 $update()

We are still missing our edit note feature lets add that to our app.js file routes.

# app/assets/javascripts/angular-app/app.js.state(‘home.edit’, {
url: ‘edit/:id’,
templateUrl: ‘home/edit.html’,
controller: ‘EditNoteController as ctrl’
})

Our new EditNoteController

# app/assets/javascripts/angular-app/controllers/EditNoteController.js
angular
.module(‘app’)
.controller(‘EditNoteController’, EditNoteController);
function EditNoteController(Note, $location, $stateParams) {
var ctrl = this;
ctrl.note = Note.get({ id: $stateParams.id }); ctrl.editNote = function() {
ctrl.note.$update(function() {
$location.path(‘notes’);
});
};
}

This will grab our current $stateParams :id an look for that id in our database. Now we can edit our note in our form.

Let’s build our edit.html form

# app/assets/javascripts/templates/home/edit.html<h1>Edit note</h1><form validate ng-submit=”ctrl.editNote()”>
<label>Title</label>
<input type=”text” ng-model=”ctrl.note.title”>
<label>Content</label>
<input type=”text” ng-model=”ctrl.note.body”>
<input type=”submit” value=”Update Note”>
</form>

It is very similar to our new.html, we just changed the function in our ng-submit. We can refactor this later into a partial, but for now we will leave it.

We now have the ability to Edit our notes, but we need a link to our new route. Lets add this to our home/notes.html:

# home/notes.html<h1>Notes</h1><ul>
<li ng-repeat=”note in ctrl.notes”>
<h3>{{ note.title }}</h3>
<p>
{{ note.body }}
</p>
<a href=”#” ui-sref=”home.note({id: note.id})”>View Note</a>
<a href=”#” ui-sref=”home.edit({id: note.id})”>Edit Note</a>
</li>
</ul>

And home/show.html:

# home/show.html<h3>{{ ctrl.note.title }}</h3>
<p>
{{ ctrl.note.body }}
</p>
<a href=”#” ui-sref=”home.edit({id: ctrl.note.id})”>Edit Note</a>

Let’s go to our browser now and edit these files.

Step: 6 $delete()

Now it is time to add the last part of CRUD. Destroy/Delete.

Let’s add the method to our NotesController.js

# controllers/NotesController.js
angular
.module(‘app’)
.controller(‘NotesController’, NotesController);
function NotesController(Note, $location, $state) { var ctrl = this; ctrl.notes = Note.query(); ctrl.deleteNote = function(note) {
note.$delete(function() {
$state.go($state.current, {}, {reload: true});
});
};
};

This will delete our note and reload our current ‘notes’ state.

Let’s add this function to our notes.html

# home/notes.html<h1>Notes</h1><ul>
<li ng-repeat=”note in ctrl.notes”>
<h3>{{ note.title }}</h3>
<p>
{{ note.body }}
</p>
<a href=”#” ui-sref=”home.note({id: note.id})”>View Note</a>
<a href=”#” ui-sref=”home.edit({id: note.id})”>Edit Note</a>
<a href ng-click=”ctrl.deleteNote(note)”>Delete Note</a>
</li>
</ul>

We should now have a delete link for our note on our ‘notes’ page. Run rails server and go to localhost:3000/#/notes and see if you can delete a note.

Congratulations!!!!

You have just completed a basic CRUD app using Angular.js and Rails.

Please leave any comments, questions or recommendations you have below.

Thanks

Links:

Part 1
Part 2
Part 3

--

--