Finding the best integration of AngularJS and Ruby on Rails
Recently I got really excited with AngularJS so to make it work perfectly with Ruby on Rails there are some configurations needed. There are available blog posts on how to integrate it perfectly but somehow I wasn’t happy with the available preferences. Some offered to add the javascript files manually to the project and to manual project organization, others offered some kind of gem packager or even automated as a rails app template.
My goal is to describe how to start new rails app project from the scratch but the instructions should be succinct enough to be able to reuse them for the existing project (Actually I did extract it from the existing application I am working on). For the front end development I recently discovered great gem that really can make it more closer to pure full stack javascript development.
Bower is a great javascript package manager by the people who are working on Twitter Boostrap. It is like Bundler but made for javascript instead of ruby language. When I found out that there is a ruby gem that is integrated with rake tasks so I can easily update all javascript libraries without needing adding gem library for each one. The gem is called bower-rails.
My initial plan is to evolve this post into a series of blog posts on how to develop a fully functional demo application so I’ve included some steps that are might not needed but are good to have. Don’t worry I will provide explanation why I am using each of them.
Here is my plan what I will try to achieve with this series of posts:
- creating a new demo project with angularJS from scratch, showing all my changes along the way, and trying to explain every step. this will include creating basic rails 4 app
- adding basic gems
- setup front end development with Bower
- adding angularJS
- implementing basic Rails and AngularJS controllers
Prerequisites
In this post we will use some of the predefined versions of libraries to make it work.
- Mac OS Yosemite operating system, though it shouldn’t be much different for *nix environment.
- Ruby 2.1.3
- Ruby on Rails 4.1.6
- AngularJS 1.3.0
- Postgresql
- Nodejs
- Bower
- Haml for writing views
- Sass for styling views
- Your favorite code editor. I am using Sublime text editor but any you feel comfortable is good enough
Initializing the new Rails 4.1.6 app
Probably you know this step already. Everyone uses them to start new rails project. We will call this application todo
and use few flags to change default settings for the test framework and use Postgresql database.
rails new todo --skip-test-unit --skip-bundle --quiet --database=postgresql
We are intentionally skipping building a bundle for now until we add additional gems to the Gemfile, configure the database and make sure we have a clean slate base on which we are going to work on.
HINT: We all are sometimes lazy so it is good to put all these arguments into ~/.railsrc
file so every time you run new generator it will reuse them without needing to write them all:
-B #Skip Bundle -T #Skip Test-Unit -d postgresql #Use postgres
now let’s continue…
<span style="background-color: #f9f9f9;">cd todo</span>
General gems that are good to have
There are usually a handful of gems that I usually add to my new project and I will go little bit in details. First of all we will need to remove turbolinks
gem from the Gemfile since it doesn’t fit the usage inside the single page application. Here are the following gems we will add:
- Common gems that are related to make develop with ease. So let’s add following lines to
Gemfile
# use haml for generators as default templating gem 'haml-rails' # better form building gem 'simple-form' # list of countries for country dropdown gem 'country_select' # nested forms gem 'nested_forms' # great addition to sass/scss functionality gem 'compass' # advanced error page for development environment, with ruby shell gem 'better_errors' gem 'binding_of_caller' # don't show asset requests in development log file gem 'quiet_assets' # making your controllers inherit all restful actions gem 'responders' # powerful alternative to the IRB gem 'pry'
- We have disabled default testing framework since I usually use RSpec and Capybara with Selenium for browser based testing of features.
group :test, :development do gem 'rspec' gem 'rspec-rails', '~> 2.0' gem 'factory_girl_rails', '~> 4.0' gem 'capybara' gem 'database_cleaner' gem 'selenium-webdriver' end
- To make it work with AngularJS I will also add two gems that are meant to support javascript libraries.
gem 'bower-rails' gem 'angular-rails-templates'
I’ve already described the bower-rails gem that giver you the power of Bower inside rails project. Angular-rails-templates gem is another one that makes rails working with angular templates much easier. It creates a cache of templates that doesn’t require AJAX requests for each template.
If some gems are not descriptive enough please do google them and read all the functionality they offer. So here is the full Gemfile file content.
source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.1.6' # Use postgresql as the database for Active Record gem 'pg' # Use SCSS for stylesheets gem 'sass-rails', '~> 4.0.3' # great addition to sass/scss functionality gem 'compass' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # Use CoffeeScript for .js.coffee assets and views gem 'coffee-rails', '~> 4.0.0' # See https://github.com/sstephenson/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby # Use jquery as the JavaScript library gem 'jquery-rails' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.0' # bundle exec rake doc:rails generates the API under doc/api. gem 'sdoc', '~> 0.4.0', group: :doc # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring', group: :development group :development do gem 'quiet_assets' gem 'better_errors' gem 'binding_of_caller' gem 'meta_request' gem 'letter_opener' gem 'rb-fsevent', require: false gem 'terminal-notifier-guard' end group :test, :development do gem 'rspec-rails', '~> 2.0' gem 'shoulda-matchers' gem 'factory_girl_rails' gem 'hirb' end group :test do gem 'email_spec' gem 'cucumber-rails', require: false gem 'guard-cucumber' gem 'database_cleaner' gem 'launchy' gem 'capybara' gem 'capybara-webkit' gem 'headless' gem 'faker' gem 'forgery' gem 'rack-test' end # AngularJS support gem 'bower-rails' gem 'angular-rails-templates' # use haml for generators as default templating gem 'haml-rails' # better form building gem 'simple_form' # list of countries for country dropdown gem 'country_select' # nested forms gem 'nested_form' # advanced error page for development environment, with ruby shell # making your controllers inherit all restful actions gem 'responders' # powerful alternative to the IRB gem 'pry' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development # Use debugger gem 'byebug', group: [:development, :test]
One things I dislike being generated
When you generate new project by default generator for models, controllers etc. usually generate a bunch of unnecessary files like helpers, stylesheets, javascript files that are dependent on the domain so to disable them we add the following code to the ./config/application.rb
:
config.generators.stylesheets = false config.generators.javascripts = false config.generators.helper = false
Configure database.yml and example database file
Since Ruby on Rails 4.1 you have new file called secrets.yml that can be used for adding private informations like database access information. So let’s modify it to be able to deploy project to repository without exposing private information.
First we add to ./.gitignore
file exception not to include secrets.yml file
config/secrets.yml
And make an example copy file for secrets template
cp config/secrets.yml config/secrets.yml.example
Now you can add details to secrets for username and password for database connection. Rewrite database.yml file to look like:
default: &default host: <%= Rails.application.secrets[:database][:host] %> adapter: postgresql encoding: UTF8 database: <%= Rails.application.secrets[:database][:name] %> pool: 10 reaping_frequency: 30 username: <%= Rails.application.secrets[:database][:username] %> password: <%= Rails.application.secrets[:database][:password] %> development: *default test: *default production: *default
And now inside secrets.yml.example file add the missing fields like:
development: secret_key_base: 2f040beb7605141a4b10a68a1121ea476cc5e86bd837bff2b9925144f013ece49c71816be0d24c721d8f9aa70519cb5c80abe3b0ffb01e12a13e6d8dc59400ab database: :host: localhost :name: todo_development :username: root :password: password test: secret_key_base: 9bb840e19afc8215aa989ee9a98e5a176f6006ce5c1fcbdc322847b6d2b57d826031996d6115675917142f3cb66186501f858aa6c0b7c308024343a07409cc71 database: :host: localhost :name: todo_test :username: root :password: password # Do not keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> database: :host: localhost :name: todo_production :username: root :password: password
Bower and front end dependency management
There is not any provided way from rails directly to manage front-end libraries and extensions that are not deployed as a gem. Tricking them and packaging them into gem as they would represent Rails Engines which are really not. We are going to use Bower to manage front-end resources for javascript supported front end development.
Here is the bower-rails gem that will merge the usefulness of only javascript full stack development and the development with rails. Prerequisite for this gem is that we have already installed npm (node package manager) that it is part of the node. Besides node library we also need to install bower library. Easiest way to install it is through homebrew, here is the following command to install them both
brew install node && npm install bower
For more details please read documentation for homebrew and npm
Let’s bundle the gems
Run bundle install
to install all the required ruby gems for our project.
Now when you see that all are successfully built let’s add all the front-end library dependencies with Bower. To install dependencies to directories let’s run the initializer to generate custom bower.json
rails g bower_rails:initialize json
We can also run rails g bower_rails:initialize
that will generate Bowerfile file that has similar syntax as Bundler’s Gemfile but for this tutorial I will rather use the same syntax with json file that is being used in javascript development.
Let’s add angularjs and angular route dependency for javascript to ./bower.json
{ "lib": { "name": "bower-rails generated lib assets", "dependencies": { "angular": "latest", "angular-route": "latest" } }, "vendor": { "name": "bower-rails generated vendor assets", "dependencies": { } } }
and run following command to install them
rake bower:install
Now when we have installed resources we can add the required javascript files to application.js file which should look like this.
//= require jquery //= require jquery_ujs //= require angular //= require angular-route //= require angular-rails-templates //= require_tree .
Let us make a folder where we will hold all the templates
mkdir app/assets/templates/
Now before trying out if everything works as needed there are few more steps to finish. First we need to remove all turbolinks references in application layout file app/views/layouts/application.html.erb
:
<%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_include_tag 'application' %> <%= csrf_meta_tags %>
Next step to do is to create database for the project
rake db:create
We can try to run server for the first time and check if everything is running okay.
rails server
If we visit http://localhost:3000/
in your favorite web browser you should see the following screen:
YES So we did it 🙂 We have everything working as it should be with no errors. If you get any problems don’t hesitate to comment below.
First AngularJS page
We don’t stop just adding all the resources without writing at least a small angularjs page to show that it works as it should be working.
Add new route to ./config/routes.rb file:
Rails.application.routes.draw do root 'home#index' end
And a accompanying controller with generator rails g controller Home index
class HomeController < ApplicationController def index end end
We need to add barebones AngularJS app so we will put this into app/assets/javascripts/app.js
file
var todo = angular.module('todoApp', []);
Last thing we need to do is to add some content to the index.html.haml
page
.container-fluid{ 'ng-app' => 'todoApp'} .panel.panel-success .panel-heading %h1{ 'ng-if' => 'name' } {{name}} .panel-body %form.form-inline .form-group %input.form-control{ type: 'text', placeholder: 'Enter your name', autofocus: 'autofocus', 'ng-model' => 'name'}
Now if you go back to the browser and refresh the page you should see the text input field. Try to write something in it should show an updated text above the field.
So here it is. We have not just added few simple javascript files to the rails pipeline but prepared a full project for front-end and back-end development where we can easy introduce the whole projects that we’ve been playing with javascript only.
Final version of the demo project should be similar to the following code on the github
Thanks! Tutorial works fine, there is only one misspelling in the code of
application.js here : “//= require angular-rails-template” -> WRONG “//= require angular-rails-templates” -> RIGHT! the letter “s” has to be placed
.. ah 2 misspellings more … “should-matchers” -> “shoulda-matchers” && “bye” -> “byebug” (now?!)
Thank you for reminding me of my typos. I hope you will do something great with rails+angular 😉