Want To Build Web Apps With Rails4 & AngularJS In 15 Minutes? Here’s How!

While learning AngularJS to make a single page app using Rails4, I found some good videos and blogs. However, I did not find any simple example for CRUD operations that made me easily understand the integration between Rails4 and AngularJS. So in this tutorial post, I explain how to create basic CRUD operation using Rails4 and AngularJS.

Here is my git repository for the complete code Github

Create rails project


$ rails new rails4_crud_with_angularjs

Create User model


$ rails g model user

file db/migrate/[timestamp]_create_users.rb


class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :phone
t.timestamps
end
end
end


$ rake db:migrate

app/model/user.rb


class User < ActiveRecord::Base
validates :first_name, :last_name, :email, presence: true
end

Create Users controller


$ rails g controller users

Create the CRUD operation in users controller and send JSON response. The code sample is here

Add angular gem

In Gemfile add these two gems.


gem 'angularjs-rails'
gem 'angular-ui-bootstrap-rails' #for bootstrap UI


$ bundle install

Setup layout

Adding ng-app and ng-view indicates that we have an AngularJS app in the page.


<html ng-app="myapplication">
<head>
<title>Rails4CrudWithAngularjs</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container" ng-view>
<%= yield %>
</div>
</body>
</html>

Create an angular controller

First let’s create a directory for our controllers. You can name it whatever you want.

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

Now create users_controllers.js file. Here I have used the same naming convention as Rails.

// app/assets/javascripts/angular/controllers/users_controllers.js
var myApp = angular.module('myapplication', ['ngRoute', 'ngResource']);

‘myapplication’ is ng-app name.

Add Factory

Factory is the angular provider and you can learn more about it here. It basically interacts with the rails server and processes the json response.

myApp.factory('Users', ['$resource',function($resource){
return $resource('/users.json', {},{
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
})
}]);

myApp.factory('User', ['$resource', function($resource){
return $resource('/users/:id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT', params: {id: '@id'} },
delete: { method: 'DELETE', params: {id: '@id'} }
});
}]);

‘Users’ factory is used for getting the collection of users and creating users. ‘User’ factory is used to get the user details, update the user or delete the user.

Add Routes

Angular routes are used for deep-linking URLs to controllers and views (HTML partials). It watches $location.url() and tries to map the path to an existing route definition.

myApp.config([
'$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider.when('/users',{
templateUrl: '/templates/users/index.html',
controller: 'UserListCtr'
});
$routeProvider.when('/users/new', {
templateUrl: '/templates/users/new.html',
controller: 'UserAddCtr'
});
$routeProvider.when('/users/:id/edit', {
templateUrl: '/templates/users/edit.html',
controller: "UserUpdateCtr"
});
$routeProvider.otherwise({
redirectTo: '/users'
});
}
]);

In the code above, I have added the controllers UserListCtr, UserAddCtr, UserUpdateCtr for listing users and to create and update users.

Add Angular templates

Now we need to add templates. I have stored them in public/templates.

If we create a file public/templates/users/index.html with some arbitrary content, we should be able to see it in the browser. Here is a sample template for users.

 CRUD Actions

Now our setup is done and we are ready for processing CRUD operation.

Index Action:

myApp.controller("UserListCtr", ['$scope', '$resource', 'Users', 'User', '$location', function($scope, $resource, Users, User, $location) {
$scope.users = Users.query(); //it's getting user collection
}]);

‘UserListCtr’ this controller listing users. you can check index.html here I am not explaining index template it’s straight forward angular template, you can read more about it here.

Create Action:

myApp.controller("UserAddCtr", ['$scope', '$resource', 'Users', '$location', function($scope, $resource, Users, $location) {
$scope.save = function () {
if ($scope.userForm.$valid){
Users.create({user: $scope.user}, function(){
$location.path('/');
}, function(error){
console.log(error)
});
}
}
}]);

‘UserAddCtr’ this controller create user. you can check new.html here. Users.create() calling users controller create action. create() action we defined in ‘Users’ factory.

Update Action:

myApp.controller("UserUpdateCtr", ['$scope', '$resource', 'User', '$location', '$routeParams', function($scope, $resource, User, $location, $routeParams) {
$scope.user = User.get({id: $routeParams.id})
$scope.update = function(){
if ($scope.userForm.$valid){
User.update($scope.user,function(){
$location.path('/');
}, function(error) {
console.log(error)
});
}
};
}]);

‘UserUpdateCtr’ this controller update the user. you can check edit.html here. Users.update() calling users controller update action. update() action we defined in ‘User’ factory.

Delete Action:

For delete user I am not creating separate angular controller. I am writing deleteUser event in ‘UserListCtr’  controller.


myApp.controller("UserListCtr", ['$scope', '$http', '$resource', 'Users', 'User', '$location', function($scope, $http, $resource, Users, User, $location) {

$scope.users = Users.query();

$scope.deleteUser = function (userId) {
if (confirm("Are you sure you want to delete this user?")){
User.delete({ id: userId }, function(){
$scope.users = Users.query();   // after delete user get users collection.
$location.path('/');
});
}
};
}]);

User.delete() calling users controller destroy action. delete() action we defined in ‘User’ factory.

In  public/templates/users/index.html for adding ‘Remove’ link


<a href="" ng-click="deleteUser(user.id)">Remove</a>

Remember href should be blank, if you add href=”#” it will call default route in your application.

I hope this blog helps those are started development in Rails + AngularJS.

18 thoughts on “Want To Build Web Apps With Rails4 & AngularJS In 15 Minutes? Here’s How!

  1. I am getting redirect to same users url when trying to create new controller e.g Emplyees
    I have done same things for an another controller Emplyees.
    can anyone help me to solve this issue.?

  2. Hi, I am trying to learn the angularjs with Rails. This example from github works perfectly fine in local but when I deploy onto Heroku, I am getting a blank screen. Looks like the templates are not getting injected. Any assistance will be greatly appreciated.

  3. I don´t get all the addresses in the controller it has anything to do with anything and confuse me of how to create a proper controller for the operations, can you please explain it and make it simple

      1. Thanks, you got this in the controller
        def user_params
        unless params[“user”][“addresses”].blank?
        params[“user”][“addresses_attributes”] = params[“user”][“addresses”]
        params[“user”].delete(“addresses”)
        end
        params.fetch(:user, {}).permit(:first_name, :last_name, :email, :phone,
        :addresses_attributes => [:id, :street1, :street2, :city, :state, :country, :zipcode, :_destroy, :user_id])
        end
        I don’t get how this works for example if user only have to params :name and :email how to rewrite def user_params

  4. @fabian above code I write for nested form, In that user has many addresses.
    In Rails when we are using nested_form gem we need addresses_attributes. it’s just mapping I am doing in def user_params. because I am getting params in params[“user”][“addresses”] so I converting in params[“user”][“addresses_attributes”].

    just for readable code in app/assets/javascripts/angular/controller/users_controller.js line 62. instead of addresses_attributes I used addresses.

    if you have only :name and :email for user then no need to add that code. like below

    def user_params
    params.fetch(:user, {}).permit(:name, :email)
    end

  5. I am using ruby 2.3.1, when I am trying to execute your code using bundle install, it fails due to json 1.8.1. I am not even able to install the json 1.8.1 gem.

  6. in the Gemfile.lock we need to update JSON 1.8.1 to 1.8.3, for compatibility.
    Other than everything worked smooth. Thanks a ton.

  7. I am trying to run this app. So far I’ve succeeded only in rendering index html. When i click on “Create a user”, URL on browser changes to “http://localhost:3000/#!/users#%2Fusers%2Fnew”, but no form is getting rendered.

    Since, This is my first trial on angular + rails combination. I doubt i might have missed something?

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.