While it is possible to include AngularJS as part of the rails assets, I think it is better to setup the angular code base on a standalone folder, leaving the rails app as a (more or less) isolated backend.
There are several advantages to this setup:
- Ability to manage the frontend app using Yeoman (including generators!).
- No more questions about file layout: use rails layout for rails stuff, angular-generator layout for angular stuff.
- Easily install external assets via bower (e.g. angularjs, jquery, twitter bootstrap, underscore, etc.).
- Write client side unit tests and run them with karma.
- Promotes unit-testing the js codebase and removes the temptation of integration-testing everything: testing with karma is a lot faster than using capybara or a similar solution.
- LiveReload support for free with yeoman's angular generator! (uses websockets, no need to install a browser plugin).
Yeoman, Bower, Livereload and Karma Runner.
I want to stress out the convinience of working on your frontend using the stack yeoman sets up for you. By keeping the frontend isolated from the backend you get an amazingly fast development environment and draw a clear line between backend and frontend (great for making sure you are writing the right unit/integration tests). Yeoman sets up the test environment for you using jasmine as the testing library and karma as the runner. karma is possibly the fastest and most complete js test runner out there. And it is very well integrated with angular.
The experience of coding with Livereload is simply amazing. Immediate feedback for every little addition you save in your code editor while you are working, without having to reload the page in the browser!
Rails was born in the request-response era of web applications, and it shows. Yeoman sets up a web environment with defaults that are better suited for developing web applications.
Setting the environment up
- ruby 1.9.3 (rvm recommended for installation)
- node 0.10.13 (nvm recommended for installation)
- Two shell sessions!
Session one: the rails backend:
rvm use 1.9.3 git clone https://github.com/EmmanuelOga/simple-angular-rails-app.git cd simple-angular-rails-app bundle install bundle exec rails s -p 3000
NOTE: the angular application was generated using these commands.
npm install -g yo generator-angular mkdir ngapp; cd ngapp yo angular notes
Session two: a grunt server
nvm use 0.10.13 cd simple-angular-rails-app/ngapp npm install -g grunt-cli npm install bower install grunt server # opens a browser window... you are done!
What's going on?
During development, you need to run both the rails app and the grunt server. The reason is the html client was written as if the rails backend was an isolated, independent service, using Yeoman to scaffold the project.
The intent is to simulate that the whole environment is a single web application. An, indeed, before deploying to prod we'll be consolidating the whole angular app as static assets in rails' public/ folder.
Here's a diagram of the stack during development:
The grunt server task proxies any url with path /api to the rails backend on localhost:3000.
Rails is used in the backend, but really any web framework would be ok here (sinatra would make a lot more sense for my silly example app!).
To run both the backend tests and front end tests, you can run:
rake test PHANTOMJS_BIN=`which phantomjs`
This is done by reopening rails's test task and adding a step to run the karma runner. This design is a bit simplistic but it works. You may want to have something a bit more elaborate to make it so angular's tests are run even if rails tests fail to complete.
The PHANTOMJS_BIN env var is needed because the project configures karma to use phantom js, but it could be changed to run any other browser.
karma can be configured to watch the tests as opposed to do a single run. You should deffinitively look into that during development.
If you run
grunt build, grunt will package the whole angular app in a
tidy package on the rails public/ folder. This packaging step could
happen in the server to avoid having to commit the generated assets in
your repository, analogous to how it is done for generating assets with
rails' assets pipeline.
The rails app sets the XSRF token in the cookies. The cookies are accessible even when using the proxy because the port is not taken into account when restricting access to the cookies.
Check ApplicationController for some notes on the XSRF protection.