rails-app-starter-kit.herokuapp.com
Please treat any data (posts, users etc.) as transient. They may not be available after a certain period of time.
For accessing via native apps, the app access token is z23498f58959thf85. See the ‘Access from Native Apps’ section for details.
A starter kit for creating applications using the Postgres, Rails and Angular stack, with the following features built-in:
-
Rails ~4.2, Angular ~1.2 (and we recommend Ruby >=2.1.2)
-
Postgres support
-
Complete user management, with authentication and role-based authorization
-
User authentication via Facebook and other providers
-
Front-end asset management using Bower
-
Angular-based routing
-
Angular-based flash messages
-
Angular interfacing with server CSRF protection and server form validation
-
Secure API-based access for native apps
-
Rails code testing using RSpec and other best practices
-
Angular and JS code testing using Teaspoon
-
Integration with the Bootstrap styling framework
-
Admin app for administrators (coming soon)
-
Ready-to-deploy on Heroku
Several ideas have been taken from angular-rails.com.
See Gemfile.lock for each gem’s version. We recommend using these versions, or newer, for best results.
If you wish to change the Ruby version, remember to also do so in the Gemfile (near the top).
Pre-requisites: You must have Node, Bower and Ruby installed.
-
Download or clone this repo
-
Run the following commands in the application’s root directory:
$ bundle install
This should set up all the gems required. Note: Installing the pg gem can be a pain. See stackoverflow.com/questions/19262312/installing-pg-gem-failure-to-build-native-extension for help.
$ rake bower:install
This should set up all the front-end assets required.
-
Create two databases named as follows, or edit /config/database.yml to suit your needs, and then create the appropriate databases:
-
rails-app-starter-kit_development (for developing)
-
rails-app-starter-kit_test (for testing)
Also change the production database details, either now, or before you wish to push your app to production. If you use Heroku, these details will be overridden anyway, but its still a good idea to change them.
-
-
Run the following command:
$ rake db:migrate
This will set up the required tables in the database.
-
Change the session key in /config/initializers/session_store.rb to suit your application.
-
If you wish to allow authentication via Facebook, create a Facebook app if you haven’t already, and set the following environment variables:
FACEBOOK_APP_ID=<Your Facebook App ID> FACEBOOK_APP_SECRET=<Your Facebook App Secret>
If you don’t want this functionality, do the following:
-
Comment out the ‘:omniauthable…’ line in /app/models/user.rb
-
Comment out the ‘controllers:…’ line with the ‘devise_for’ directive in /config/routes.rb
-
-
If you wish to allow API-based access for native apps, set the following environment variable:
APP_ACCESS_TOKEN=<Some random string>
You must then send this token with each request, in the ‘X-App-Access-Token’ header.
The application structure is similar to a standard Rails app, with certain additions, a sampling of which is shown below:
app |- assets |- javascripts |- admin (for the admin app) |- client (for the main 'non-admin' app) |- shared (common to main and admin app) |- angular (contains all Angular code) |- app.js (the 'entry point' for Angular) |- routes.js.erb |- controllers |- directives |- modules (self-contained 'packages' of functionality) |- templates (contains all Angular templates, i.e. views) |- admin |- client |- shared |- stylesheets (contains all CSS styles) |- controllers |- admin (all admin controllers) |- home_controller.rb (the 'entry point' controller) |- jobs (contains all background jobs) |- policies (access authorization policies) |- admin (all admin authorization policies) |- views |- admin (all admin views) |- home |- index.html (the 'entry point' view) spec (contains all tests) |- support (utility stuff for testing) |- javascripts (contains all JS and Angular tests) vendor |- assets |- bower_components (all front-end components mananged by Bower)
The ‘admin’ folders contain files related to the admin app. This will be discussed towards the end of this README. Until then, the sections below are written from the point of view of the client (i.e. main or ‘non-admin’) part of the app. As it happens much of this information also holds true for the admin app!
Rails generators have been configured not to generate non-useful files such as assets, helpers, views, or view specs. This is because we are using Angular as our main MVC framework and not Rails.
We use the ‘annotate’ gem to add column information to models. Without this, it is difficult to know at a glance the columns within a model table. Run this gem generally after you run a migration, as follows:
$ annotate --position before
Normally, Rails does asset management from within the (/app/lib/vendor)/assets folders. However, because we are supporting very ‘front-end heavy’ applications, we use Bower, which is the most widely used such tool. We use the ‘bower-rails’ gem for this purpose. See the following for more information:
To add/remove front-end libraries, add-to/remove-from the /bower.json file the required library or libraries. Then run:
$ rake bower:install
Also remember to reference/de-reference the relevant files in application.js, and/or application.css.
We use RSpec (instead of the default TestUnit) for Rails code testing. See the following for more information:
We use FactoryGirl for creating real or mock objects required for testing. See the following for more information:
We use Teaspoon (which supports several test frameworks - Jasmine, Mocha and QUnit) for JS and Angular code testing. See github.com/modeset/teaspoon for more information.
For a detailed discussion on testing, see the Testing section later on.
Authentication is done via the ‘devise’ gem (see github.com/plataformatec/devise). Users are stored in the ‘User’ model.
The entire devise workflow is, after weighing the pros and cons, deliberately kept outside of Angular. See medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec for a detailed discussion; note however that our implementation is different. Relevant files in our implementation are:
-
/app/assets/javascripts/shared/angular/directives/authentication_links.js
-
/app/controllers/application_controller (the ‘set_sign_in_redirect’ method)
-
All devise related files, of course
In the JS and Angular code, the currently signed in user details are available through the ‘AuthSvc’ service. We have also provided helper methods to control access to certain routes. See the following for more details:
-
/app/assets/javascripts/client/angular/routes.js
-
/app/assets/javascripts/shared/angular/services/auth_svc.js
We also provide authentication with Facebook out of the box, as well as easy integration of other providers such as Google, Twitter and more.
See the ‘Setting Up’ section for how to enable Facebook authentication.
COMING SOON…
Authorization in the Ruby code is done via two gems:
Authorization policies are placed in /app/policies.
In JS and Angular code, role-based authorization has been implemented to the extent of route access. See the Authentication section above.
Form validation should generally take place at the Angular end. However, this may not always be possible, and you may choose to leave some validation exclusively on the server-side.
We provide a clean integration between Angular form validation and server-side form validation via the ‘formErrors’ directive. See /app/assets/javascripts/shared/angular/directives/form_errors.js.
We provide DelayedJob for running background jobs. For most apps, this is sufficient. However, switching to Resque, Sidekiq etc. is very easy, since the actual jobs can be written using the Rails 4.2 ActiveJob “facade”. For more information see:
We include Bootstrap as the styling library of choice. Unlike other front-end assets, we include it as a gem, rather than through Bower, as this allows for much easier integration and customization.
To reduce the application size, comment out the modules you don’t require in these two files:
-
assets/stylesheets/bootstrap-custom.scss
-
assets/javascripts/bootstrap-custom.js
We also provide some guidelines on how to structure CSS/SCSS files. For more information see:
Secure access from native apps is achieved by requiring an ‘app access token’ along with each request, in the ‘X-App-Access-Token’ header. Remember to carry out all communication over HTTPS, to prevent the access token from being sniffed.
See the ‘Setting Up’ section for how to create a valid app access token.
Errors from any endpoint can be in one of the following two formats:
{ "error": "some error" } OR { "errors": { "some-key": "some error", ... } }
New users can be registered via the following endpoint:
/api/users/sign_up
The following information needs to be sent:
{ user: { "email": "[email protected]", "password": "somepassword" } }
If the user is registered successfully, the user’s details are returned, as follows:
{ user: { "id": 434899 (for example), "email": "[email protected]", "confirmed": false (or true), "authentication_token": "sometoken" (if authenticated after creation) } }
To delete a user, send a DELETE request to the following endpoint:
/api/users
Deletion only succeeds in one case: a signed in user deleting itself.
See the following files for more:
-
/app/controllers/api/users/registrations_controller.rb
-
/app/views/api/users/registrations/create.json.jbuilder
To authenticate a user with an email and password, send a request identical to the regitsration request, to the following endpoint:
/api/users/sign_in
If the user is authenticated successfully, the user’s details are returned as follows:
{ user: { "id": 434899, "email: "[email protected], "authentication_token": "sometoken" } }
To authenticate a user via Facebook or another provider, send a request to the same endpoint, as follows:
{ user: { "provider": "facebook" (or other), "uid": 12309939 (i.e. the provider's ID for the user), "email": "[email protected]" } }
If a user corresponding to the provider and UID exists, it is signed in. Otherwise, a new user is created using the email address provided, and if the user creation is successful, is signed in. The response is as above.
For more on both password and provider based authentication, see:
-
/app/controllers/api/users/sessions_controller.rb
-
/app/views/api/users/sessions/create.json.jbuilder
To make an authenticated request to any endpoint, include the user’s email and authentication token (see above) in the following request headers:
-
X-User-Email
-
X-User-Authentication-Token
Testing is a vast subject, best learnt from hands-on experience. See the following for ideas on how to get started:
Most tests require the use of real or mock objects against which tests can be run. We use FactoryGirl and rspec-mocks for creating such objects. Each has its advantages, and when to choose which is beautifully explained here: www.agileventures.org/articles/testing-with-rspec-stubs-mocks-factories-what-to-choose.
Many controller tests require a user (possibly having certain roles) to be signed in. We have provided integration with devise for easy authentication. See the following for more information:
-
/spec/factories/users.rb
-
/spec/support/controller_macros.rb
We provide an easy way to test authorization policies generated using pundit. See /spec/support/pundit_matcher.rb for relevant RSpec matchers.
Authorization policy tests are placed in /spec/policies.
Coming soon.
Coming soon.
We have tried to keep the admin app as separate from the client (main) app as possible.
The admin landing page has its own layout, so in theory, one can use a completely different set of front-end tools for it. However, to get you started, we provide a skeleton app using many of the same libraries as the client app.
The code is organized as follows:
-
All admin related server-side code lives within ‘admin’ folders.
-
All admin related front-end code lives ‘admin’ folders in app/assets. Here, the only difference is that the client app code is put into ‘client’ folders, and the shared code in ‘shared’ folders. This enables easy inclusion of desired files into the client/admin application.(js/scss) files.
Rails models are typically shared between the client and admin apps. However, controllers and views are separate.
DataTables forms an integral part of the admin app, giving admins the ability to filter, sort and edit data conveniently.
It is included directly from a CDN, and not through the asset pipeline, since the latter results in complications, and the former seems to suffice. See /app/views/layouts/admin/application.html.erb.
For more on DataTables, see datatables.net.
-
Run:
rails g resource Widget (substitute Widget with resource name)
OR
rails g model Widget rails g controller Widgets
-
Edit the /config/routes.rb file
-
Write some model unit tests. For reference see:
-
/spec/models/post_spec.rb
-
/spec/factories/posts.rb
-
-
Write some model functionality
-
Create an authorization policy. For reference see /app/policies/post_policy.rb.
-
Write some controller unit tests. For reference see /spec/controllers/posts_controller_spec.rb.
-
Write some authorization policy tests. For reference see /spec/policies/post_policy_spec.rb.
-
Write some controller functionality
-
Write the server views (which basically render out responses as JSON). For reference, see /app/views/posts/index.json.jbuilder. JBuilder (github.com/rails/jbuilder) comes bundled with Rails, and is a much better way to create JSON, than using the ‘as_json’ method.
-
Create an Angular resource to communicate with the controller. See /app/assets/javascripts/shared/angular/services/post.js.
-
Create an Angular controller that uses the resource. For reference see /app/assets/javascripts/client/angular/controllers/posts_ctrl.js.
-
Write some Angular controller unit tests. For reference see /app/spec/javascripts/client/controllers/home_ctrl_spec.js.
-
Create an Angular view (template). For reference see /app/assets/javascripts/templates/client/controllers/posts/index.html.
-
Update the /app/assets/javascripts/client/angular/routes.js file
-
Create any directives that may be required for the view
-
Write some directive unit tests
When creating an API, you will likely want to render JSON error messages in a consistent format, from any controller action.
The ‘render_op_error’ method defined in the application controller lets you do this in a flexible manner, and even supports localization.
See its documentation here: /app/controllers/application_controller.rb.
It can sometimes be useful to expose some data or service to all controllers (and consequently views). One example is the ‘AuthSvc’, since most controllers and views are likely to use authentication services in one way or another; for example, showing an ‘Edit’ link for a post only for the owner of the post.
This can be done in the ‘AppCtrl’, our Angular equivalent of Rails’ ApplicationController. Anything added to its scope becomes available to every controller and view.
See /app/assets/javascripts/client/angular/controllers/app_ctrl.js.
-
Lines are kept within 80 characters
-
2 spaces are used as tabs, with 4 spaces for continuation
-
Ruby comments are compatible with Yard. For more information, see:
-
General Rules
-
Single-line-single-sentence comments do not end with a full-stop
-
Multiple-line or multiple-sentence comments end with a full-stop
-
All comments are in sentence case
-
Multiple-line comments can be written using the /../ style, in which case, the opening /* must be an empty line
-
Contains everything that didn’t fit in anywhere else on this README.
This README is compatible with RDoc.