Find file
Fetching contributors…
Cannot retrieve contributors at this time
886 lines (861 sloc) 67.9 KB
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Rails Tutorial for Devise with CanCan and Twitter Bootstrap &#183; RailsApps</title>
<link href="https://plus.google.com/u/0/b/117374718581973393536/117374718581973393536/posts/" rel="publisher" />
<link rel="stylesheet" href="http://railsapps.github.com/css/bootstrap.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="http://railsapps.github.com/css/screen.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="http://railsapps.github.com/css/gollum.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="http://railsapps.github.com/css/site.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="http://railsapps.github.com/css/syntax.css" type="text/css" charset="utf-8" />
<script src="http://code.jquery.com/jquery-1.6.min.js" type="text/javascript"></script>
<script src="http://railsapps.github.com/javascript/jquery.text_selection-1.0.0.min.js" type="text/javascript"></script>
<script src="http://railsapps.github.com/javascript/jquery.previewable_comment_form.js" type="text/javascript"></script>
<script src="http://railsapps.github.com/javascript/jquery.tabs.js" type="text/javascript"></script>
<script src="http://railsapps.github.com/javascript/gollum.js" type="text/javascript"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-5109366-14']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a href="http://railsapps.github.com/" class="brand">RailsApps Project</a>
<ul class="pull-right nav">
<li><a href="http://blog.railsapps.org/" class="twitter">Blog</a></li>
<li><a href="http://twitter.com/rails_apps" class="twitter">Twitter</a></li>
<li><a href="https://plus.google.com/117374718581973393536" class="google">Google +</a></li>
<li><a href="https://github.com/RailsApps" class="github">GitHub Repository</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="content wikistyle gollum textile">
<h1>Rails Tutorial for Devise with CanCan and Twitter Bootstrap</h1>
<h4>by Daniel Kehoe</h4>
<p><em>Last updated 23 June 2012</em></p>
<p>Ruby on Rails tutorial showing how to create a Rails 3.2 application using <strong>Devise</strong> with <strong>CanCan</strong> and <strong>Twitter Bootstrap</strong>.</p>
<ul>
<li>
<a href="http://github.com/plataformatec/devise">Devise</a> gives you ready-made authentication and user management.</li>
<li>
<a href="https://github.com/ryanb/cancan">CanCan</a> provides authorization which restricts what resources a given user is allowed to access.</li>
<li>
<a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a> is a front-end framework for <span class="caps">CSS</span> styling.</li>
</ul><p><img src="http://railsapps.github.com/images/rails3-bootstrap-devise-cancan.png" title="Rails Application for Devise with CanCan and Twitter Bootstrap" alt="Rails Application for Devise with CanCan and Twitter Bootstrap"></p>
<p>You can create the example app from this tutorial or clone the <a href="http://github.com/RailsApps/rails3-bootstrap-devise-cancan/">rails3-bootstrap-devise-cancan</a> repository for the complete application. If you want to use the project as a starter app for your own customized application, see the <a href="https://github.com/RailsApps/rails3-bootstrap-devise-cancan">rails3-bootstrap-devise-cancan <span class="caps">README</span></a> to use an application template to generate a your own version of the example app. Generating the application gives you many options, such as using Haml for views, additional Devise modules, and other popular gems such as will-paginate.</p>
<h3>RailsApps Examples and Tutorials</h3>
<p>This is one in a series of Rails example apps and tutorials from the <a href="http://railsapps.github.com/">RailsApps Project</a>. See a list of similar <a href="http://railsapps.github.com/rails-examples-tutorials.html">Rails examples, tutorials, and starter apps</a>.</p>
<p>This example application is based on the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> example and tutorial and adds <a href="https://github.com/ryanb/cancan">CanCan</a> and <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a>. View the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> example and tutorial for the basics of setting up an application with <a href="http://rspec.info/">RSpec</a> and <a href="http://cukes.info/">Cucumber</a>.</p>
<p>This example application uses ActiveRecord and a SQLite database. You can use the Mongoid <span class="caps">ORM</span> with the MongoDB datastore instead, for faster development without schemas or migrations. The <a href="https://github.com/RailsApps/rails3-mongoid-devise">rails3-mongoid-devise</a> example app and tutorial shows how to set up Devise and Mongoid with RSpec and Cucumber.</p>
<p>To see a more complex application that uses Devise, CanCan, and Twitter Bootstrap, see the <a href="https://github.com/RailsApps/rails-prelaunch-signup">rails-prelaunch-signup</a> example and tutorial from the RailsApps project.</p>
<h2>
<a href="http://www.twitter.com/rails_apps"><img src="http://twitter-badges.s3.amazonaws.com/t_logo-a.png" title="Follow on Twitter" alt="Follow on Twitter"></a> Follow on Twitter</h2>
<p>Follow the project on Twitter: <a href="http://twitter.com/rails_apps">rails_apps</a>. Tweet some praise if you like what you’ve found.</p>
<h2>
<img src="http://railsapps.github.com/images/rails-36x36.jpg" title="Tutorial" alt="Tutorial"> Tutorial</h2>
<p>This tutorial documents each step that you must follow to create this application. Every step is documented concisely, so a complete beginner can create this application without any additional knowledge. However, no explanation is offered for any of the steps, so if you are a beginner, you’re advised to look for an introduction to Rails elsewhere. See resources for getting started with <a href="http://railsapps.github.com/rails.html">Rails</a>.</p>
<h2>Before You Start</h2>
<p>If you follow this tutorial closely, you’ll have a working application that closely matches the example app in this GitHub repository. The example app in the <a href="http://github.com/RailsApps/rails3-bootstrap-devise-cancan/">rails3-bootstrap-devise-cancan</a> repository is your reference implementation. If you find problems with the app you build from this tutorial, download the example app (in Git speak, clone it) and use a file compare tool to identify differences that may be causing errors. On a Mac, <a href="http://stackoverflow.com/questions/187064/graphical-diff-for-mac-os-x">good file compare tools</a> are <a href="http://en.wikipedia.org/wiki/Apple_Developer_Tools#FileMerge">FileMerge</a>, <a href="http://sourcegear.com/diffmerge/">DiffMerge</a>, <a href="http://www.kaleidoscopeapp.com/">Kaleidoscope</a>, or Ian Baird’s <a href="http://www.changesapp.com/">Changes</a>.</p>
<p>If you clone and install the example app and find problems or wish to suggest improvements, please create a <a href="http://github.com/RailsApps/rails3-bootstrap-devise-cancan/issues">GitHub issue</a>.</p>
<p>To improve this tutorial, please edit this wiki page or leave comments below.</p>
<h2>Creating the Application</h2>
<h3>Option One</h3>
<p><em>Follow this tutorial.</em></p>
<p>To create the application, you can cut and paste the code from the tutorial into your own files. It’s a bit tedious and error-prone but you’ll have a good opportunity to examine the code closely.</p>
<h3>Option Two</h3>
<p><em>Use the ready-made application template to generate the code.</em></p>
<p>You can use an application template to generate a new Rails app with code that closely matches the tutorial. You’ll find an application template for this tutorial in the <a href="https://github.com/RailsApps/rails3-application-templates">Rails Application Templates</a> repository.</p>
<p>You’ll be able to give it your own project name when you generate the app. Generating the application (described below) gives you many options, such as using Haml for views, additional Devise modules, and other popular gems such as will-paginate.</p>
<p>Use the command:</p>
<pre>
$ rails new rails3-bootstrap-devise-cancan -m https://raw.github.com/RailsApps/rails3-application-templates/master/rails3-bootstrap-devise-cancan-template.rb -T
</pre>
<p>Use the <code>-T</code> flag to skip Test::Unit files.</p>
<p>The <code>$</code> character indicates a shell prompt; don’t include it when you run the command.</p>
<p>This creates a new Rails app named <code>rails3-bootstrap-devise-cancan</code> on your computer. You can use a different name if you wish.</p>
<p>The application generator template will ask you for your preferences.</p>
<p>To produce an application exactly like the tutorial, make the following selections:</p>
<ul>
<li>Would you like to use <a href="http://en.wikipedia.org/wiki/Haml">Haml</a> instead of <span class="caps">ERB</span>? <strong>no</strong>
</li>
<li>Would you like to use <a href="http://rspec.info/">RSpec</a> instead of TestUnit? <strong>yes</strong>
</li>
<li>Would you like to use <a href="https://github.com/thoughtbot/factory_girl">factory_girl</a> for test fixtures with RSpec? <strong>yes</strong>
</li>
<li>Would you like to use <a href="https://github.com/notahat/machinist">machinist</a> for test fixtures with RSpec? <strong>no</strong>
</li>
<li>Would you like to use <a href="http://cukes.info/">Cucumber</a> for your <span class="caps">BDD</span>? <strong>yes</strong>
</li>
<li>Would you like to use <a href="http://intridea.com/posts/hire-a-guard-for-your-project">Guard</a> to automate your workflow? <strong>no</strong>
</li>
<li>How will you send email? <strong>#2</strong>
<ol>
<li>
<span class="caps">SMTP</span> account</li>
<li>Gmail account</li>
<li>SendGrid account</li>
</ol>
</li>
<li>Would you like to use <a href="http://github.com/plataformatec/devise">Devise</a> for authentication? <strong>#2</strong>
<ol>
<li>No</li>
<li>Devise with default modules</li>
<li>Devise with Confirmable module</li>
<li>Devise with Confirmable and Invitable modules</li>
</ol>
</li>
<li>Would you like to manage authorization with <a href="https://github.com/ryanb/cancan">CanCan</a> &amp; <a href="https://github.com/EppO/rolify">Rolify</a>? <strong>yes</strong>
</li>
<li>Which front-end framework would you like for HTML5 and CSS3? <strong>#4</strong>
<ol>
<li>None</li>
<li><a href="http://foundation.zurb.com/">Zurb Foundation</a></li>
<li>
<a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a> (less)</li>
<li>
<a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a> (sass)</li>
<li><a href="http://www.getskeleton.com/">Skeleton</a></li>
<li>Normalize <span class="caps">CSS</span> for consistent styling</li>
</ol>
</li>
<li>Which form gem would you like? <strong>#1</strong>
<ol>
<li>None</li>
<li>simple form</li>
<li>simple form (bootstrap)</li>
</ol>
</li>
<li>Would you like to use <a href="https://github.com/josevalim/rails-footnotes">rails-footnotes</a> during development? <strong>no</strong>
</li>
<li>Would you like to set a robots.txt file to ban spiders? <strong>yes</strong>
</li>
<li>Would you like to add ‘will_paginate’ for pagination? <strong>no</strong>
</li>
</ul><p>Be sure to choose the <em>CanCan &amp; Rolify</em> option as well as the <em>Twitter Bootstrap (sass)</em> option to create the example application.</p>
<p>You can choose other selections if you don’t care about matching the example application exactly.</p>
<p>You can choose the <strong>Devise with Confirmable module</strong> option if you want new users to confirm their email address before gaining access to your site. If you don’t wish to require email confirmation, choose the option <strong>Devise with default modules</strong>.</p>
<h3>Option Three</h3>
<p><em>Use the <a href="https://github.com/RailsApps/rails_apps_composer">rails_apps_composer</a> gem to create a reusuable application template.</em></p>
<p>This is optimal if you are creating a “starter app” based on this example app but wish to customize the code for your own preferences.</p>
<p>Each step in this tutorial has a corresponding application template recipe from the <a href="https://github.com/RailsApps/rails_apps_composer">Rails Apps Composer</a> recipes repository. You can create your own application template using the template recipes. To do so, clone the <a href="https://github.com/RailsApps/rails_apps_composer">Rails Apps Composer</a> project, customize recipes as needed, and follow the instructions to create a reusable application template file.</p>
<h2>Assumptions</h2>
<p>Before beginning this tutorial, you need to install</p>
<ul>
<li>The Ruby language (version 1.9.3 or newer)</li>
<li>Rails 3.2</li>
</ul><p>Check that appropriate versions of Ruby and Rails are installed in your development environment:</p>
<p><code>$ ruby -v</code><br><code>$ rails -v</code></p>
<p>Be sure to read <a href="http://railsapps.github.com/installing-rails.html">Installing Rails</a> for detailed instructions and advice.</p>
<h2>Create the Rails Application</h2>
<p>Beginning here, we show how to create the application from scratch.</p>
<p>Open a terminal, navigate to a folder where you have rights to create files, and type:</p>
<p><code>$ rails new rails3-bootstrap-devise-cancan -T</code></p>
<p>Use the <code>-T</code> flag to skip Test::Unit files (since you are using RSpec).</p>
<p>You may give the app a different name if you are building it for your own use. For this tutorial, we’ll assume the name is “rails3-bootstrap-devise-cancan.”</p>
<p>This will create a Rails application that uses a SQLite database for data storage.</p>
<p>After you create the application, switch to its folder to continue work directly in that application:</p>
<p><code>$ cd rails3-bootstrap-devise-cancan</code></p>
<h3>Edit the <span class="caps">README</span>
</h3>
<p>If you’re open sourcing the app on GitHub, please edit the <span class="caps">README</span> file to add a description of the app and your contact info. Changing the <span class="caps">README</span> is important if you’re using a clone of the example app. I’ve been mistaken (and contacted) as the author of apps that are copied from my example.</p>
<h2>Set Up Source Control (Git)</h2>
<p>If you’re creating an app for deployment into production, you’ll want to set up a source control repository at this point. If you are building a throw-away app for your own education, you may skip this step.</p>
<p><code>$ git init .</code><br><code>$ git add .</code><br><code>$ git commit -m 'Initial commit'</code></p>
<p>See detailed instructions for <a href="http://railsapps.github.com/rails-git.html">Using Git with Rails</a>.</p>
<h2>Set Up Gems</h2>
<h3>About Required Gems</h3>
<p>The application uses the following gems:</p>
<ul>
<li><a href="http://rubygems.org/gems/rails">rails</a></li>
<li><a href="http://rubygems.org/gems/rspec-rails">rspec-rails</a></li>
<li><a href="http://rubygems.org/gems/database_cleaner">database_cleaner</a></li>
<li><a href="http://rubygems.org/gems/factory_girl_rails">factory_girl_rails</a></li>
<li><a href="http://rubygems.org/gems/email_spec">email_spec</a></li>
<li><a href="http://rubygems.org/gems/cucumber-rails">cucumber-rails</a></li>
<li><a href="http://rubygems.org/gems/capybara">capybara</a></li>
<li><a href="http://rubygems.org/gems/devise">devise</a></li>
<li><a href="http://rubygems.org/gems/cancan">cancan</a></li>
<li><a href="http://rubygems.org/gems/rolify">rolify</a></li>
<li><a href="http://rubygems.org/gems/bootstrap-sass">bootstrap-sass</a></li>
</ul><h3>Set up Your Gemfile</h3>
<p>It’s a good idea to create a new gemset using rvm, the <a href="http://rvm.beginrescueend.com/">Ruby Version Manager</a>, as described in the article <a href="http://railsapps.github.com/installing-rails.html">Installing Rails</a>.</p>
<p>See <a href="http://railsapps.github.com/rails-3-2-example-gemfile.html">Example Gemfiles for Rails 3.2</a>.</p>
<p>Open your <strong>Gemfile</strong> and replace the contents with the following:</p>
<p><strong>Gemfile</strong></p>
<pre>
source 'https://rubygems.org'
gem 'rails', '3.2.6'
gem 'sqlite3'
group :assets do
gem 'sass-rails', '~&gt; 3.2.3'
gem 'coffee-rails', '~&gt; 3.2.1'
gem 'uglifier', '&gt;= 1.0.3'
end
gem 'jquery-rails'
gem "rspec-rails", "&gt;= 2.9.0.rc2", :group =&gt; [:development, :test]
gem "factory_girl_rails", "&gt;= 3.1.0", :group =&gt; [:development, :test]
gem "email_spec", "&gt;= 1.2.1", :group =&gt; :test
gem "cucumber-rails", "&gt;= 1.3.0", :group =&gt; :test
gem "capybara", "&gt;= 1.1.2", :group =&gt; :test
gem "database_cleaner", "&gt;= 0.7.2", :group =&gt; :test
gem "launchy", "&gt;= 2.1.0", :group =&gt; :test
gem "devise", "&gt;= 2.1.0.rc"
gem "cancan", "&gt;= 1.6.7"
gem "rolify", "&gt;= 3.1.0"
gem "bootstrap-sass", "&gt;= 2.0.1"
</pre>
<p>Check for the <a href="http://rubygems.org/gems/rails">current version of Rails</a> and replace <code>gem 'rails', '3.2.6'</code> accordingly.</p>
<p><em>Note:</em> The RailsApps examples are generated with application templates created by the <a href="https://github.com/RailsApps/rails_apps_composer">Rails Apps Composer Gem</a>. For that reason, groups such as <code>:development</code> or <code>:test</code> are specified inline. You can reformat the Gemfiles to organize groups in an eye-pleasing block style. The functionality is the same.</p>
<h3>Install the Required Gems</h3>
<p>Install the required gems on your computer:</p>
<p><code>$ bundle install</code></p>
<p>You can check which gems are installed on your computer with:</p>
<p><code>$ gem list --local</code></p>
<p>Keep in mind that you have installed these gems locally. When you deploy the app to another server, the same gems (and versions) must be available.</p>
<h2>Configuration for Haml</h2>
<p>In this tutorial, we’ll use the default “<span class="caps">ERB</span>” Rails template engine. Optionally, you can use another template engine, such as Haml. See instructions for <a href="http://railsapps.github.com/rails-haml.html">adding Haml to Rails</a>.</p>
<h2>Add RSpec for Unit Testing</h2>
<p>The <a href="http://railsapps.github.com/tutorial-rails-devise-rspec-cucumber.html">rails3-devise-rspec-cucumber tutorial</a> shows how to set up RSpec and provides example specs for use with Devise.</p>
<h2>Add Cucumber for Behavior Driven Development</h2>
<p>The <a href="http://railsapps.github.com/tutorial-rails-devise-rspec-cucumber.html">rails3-devise-rspec-cucumber tutorial</a> shows how to set up Cucumber and provides example scenarios for use with Devise.</p>
<h2>Test the App</h2>
<p>You can check that your app runs properly by entering the command</p>
<p><code>$ rails server</code></p>
<p>To see your application in action, open a browser window and navigate to <a href="http://localhost:3000">http://localhost:3000/</a>. You should see the Rails default information page.</p>
<p>Stop the server with Control-C.</p>
<h2>Configure Email</h2>
<p><em>The “Configure Email” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<p>You must configure the app for your email account if you want your application to send email messages, for example, if you’ve generated the application with the option to install the Devise <code>:confirmable</code> module.</p>
<h3>Configure ActionMailer</h3>
<p>Remove the following from the <strong>config/environments/development.rb</strong> file:</p>
<pre>
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
</pre>
<p>Add the following to the <strong>config/environments/development.rb</strong> file:</p>
<pre>
# ActionMailer Config
config.action_mailer.default_url_options = { :host =&gt; 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
# change to false to prevent email from being sent during development
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default :charset =&gt; "utf-8"
</pre>
<p>Add the following to the <strong>config/environments/production.rb</strong> file:</p>
<pre>
config.action_mailer.default_url_options = { :host =&gt; 'example.com' }
# ActionMailer Config
# Setup for production - deliveries, no errors raised
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default :charset =&gt; "utf-8"
</pre>
<p>Add the following to the <strong>config/environments/test.rb</strong> file:</p>
<pre>
# ActionMailer Config
config.action_mailer.default_url_options = { :host =&gt; 'example.com' }
</pre>
<p>This will set the example application to deliver email in both development and production. It will raise delivery errors in development but not production.</p>
<p>In development, <code>config.action_mailer.default_url_options</code> is set for a host at <code>localhost:3000</code> which will enable links in Devise confirmation email messages to work properly during development.</p>
<p>For testing, <code>config.action_mailer.default_url_options</code> is set for a host at <code>example.com</code>. Any value allows tests to run.</p>
<p>For production, you’ll need to change the <code>config.action_mailer.default_url_options</code> host option from <code>example.com</code> to your own domain.</p>
<h3>Use a Gmail account</h3>
<p>If you want to use a Gmail account to send email, you’ll need to modify the files <strong>config/environments/development.rb</strong> and <strong>config/environments/production.rb</strong>:</p>
<pre>
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: "example.com",
authentication: "plain",
enable_starttls_auto: true,
user_name: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
</pre>
<p>You can replace <code>ENV["GMAIL_USERNAME"]</code> and <code>ENV["GMAIL_PASSWORD"]</code> with your Gmail username and password. However, committing the file to a public GitHub repository will expose your secret password.</p>
<p>If you’re familiar with setting <a href="http://en.wikipedia.org/wiki/Environment_variable">Unix environment variables</a>, it’s advisable to leave <code>config.action_mailer.smtp_settings</code> unchanged and set your environment variables in the file that is read when starting an interactive shell (the <strong>~/.bashrc</strong> file for the bash shell). This will keep the password out of your repository.</p>
<p>Are you using a bash shell? Use <code>echo $SHELL</code> to find out. For a bash shell, edit the <strong>~/.bashrc</strong> file and add:</p>
<pre>
export GMAIL_USERNAME="myname@gmail.com"
export GMAIL_PASSWORD="secret*"
</pre>
<p>Open a new shell or restart your terminal application to continue.</p>
<h2>Set Up Authentication</h2>
<p><em>The “Set Up Authentication” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<p>This app uses <a href="http://github.com/plataformatec/devise">Devise</a> for user management and authentication.</p>
<h3>Set Up Configuration for Devise</h3>
<p>You should have the following gem in your <strong>Gemfile</strong> file:</p>
<pre>
gem 'devise'
</pre>
<p>If you haven’t already, run:</p>
<p><code>$ bundle install</code></p>
<p>Run the generator to install Devise:</p>
<p><code>$ rails generate devise:install</code></p>
<p>which installs a configuration file:</p>
<p><strong>config/initializers/devise.rb</strong></p>
<p>and a localization file.</p>
<h3>Configure Devise for Email</h3>
<p>Complete your email configuration by modifying</p>
<p><strong>config/initializers/devise.rb</strong></p>
<p>and setting the <code>config.mailer_sender</code> option for the return email address for messages that Devise sends from the application.</p>
<h3>Generate a Model and Routes for Users</h3>
<p>Use Devise to generate models and routes for a User.</p>
<pre>
$ rails generate devise User
</pre>
<p>Devise will create a database migration and a User model.</p>
<p>Devise will try to create a spec file for the User model. If you’ve already downloaded the example app spec files, don’t let the Devise generator overwrite the <strong>spec/models/user_spec.rb</strong> file.</p>
<p>Devise will modify the <strong>config/routes.rb</strong> file to add:</p>
<pre>
devise_for :users
</pre>
<p>which provides a complete set of routes for user signup and login. If you run <code>rake routes</code> you can see the routes that this line of code creates.</p>
<h3>Accommodate Cucumber Testing for “Sign Out”</h3>
<p>By default, Devise uses an http <span class="caps">DELETE</span> request for sign out requests (<code>destroy_user_session_path</code>). Rails uses Javascript to implement http <span class="caps">DELETE</span> requests. Prior to Devise 1.4.1 (27 June 2011), Devise used an http <span class="caps">GET</span> request for sign out requests. Jose Valim explained the change: “<span class="caps">GET</span> requests should not change the state of the server. When sign out is a <span class="caps">GET</span> request, <span class="caps">CSRF</span> can be used to sign you out automatically and things that preload links can eventually sign you out by mistake as well.”</p>
<p>However, Cucumber wants to test <span class="caps">GET</span> requests not <span class="caps">DELETE</span> requests. If you intend to use Cucumber with Devise, you must change the Devise default from <span class="caps">DELETE</span> to <span class="caps">GET</span> in <strong>/config/initializers/devise.rb</strong> for the Rails test environment. You may see a suggestion elsewhere to tweak the routes.rb file or change the log_out link to make the fix. It isn’t necessary if you change the <strong>/config/initializers/devise.rb</strong> file.</p>
<pre>
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = Rails.env.test? ? :get : :delete
</pre>
<p>Since you only use Cucumber during testing, switching the default is only needed for testing.</p>
<p>If you’re not going to use Cucumber, leave Devise’s default (<span class="caps">DELETE</span>) in place.</p>
<h3>Prevent Logging of Passwords</h3>
<p>We don’t want passwords written to our log file.</p>
<p>Modify the file <strong>config/application.rb</strong> to include:</p>
<pre>
config.filter_parameters += [:password, :password_confirmation]
</pre>
<p>Note that filter_parameters is an array.</p>
<h2>Set Up Authorization</h2>
<p><em>The <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial does not include a “Set Up Authorization” step.</em></p>
<p>Devise provides authentication, a system to securely identify users, making sure the user is really who he represents himself to be. We need to add a system for authorization to determine if an authenticated user should have access to secured resources. This app uses <a href="https://github.com/ryanb/cancan">CanCan</a> for authorization, to restrict access to pages that should only be viewed by an administrator. Cancan is by far the most popular gem used to implement authorization (see the Rails Authorization category on <a href="https://www.ruby-toolbox.com/categories/rails_authorization">The Ruby Toolbox</a> site) . The author of CanCan, Ryan Bates, offers a <a href="http://railscasts.com/episodes/192-authorization-with-cancan">RailsCast on Authorization with CanCan</a> to show how to use it.</p>
<p>There are many ways to implement authorization in a web application. CanCan offers an architecture that centralizes all authorization rules (permissions or “abilities”) in a single location, the CanCan <code>Ability</code> class. For a discussion of the benefits of using a single, consolidated location for the permissions, see the article <a href="http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/">Don’t Do Role-Based Authorization Checks; Do Activity-Based Checks</a>.</p>
<p>CanCan provides a mechanism for limiting access at the level of controller and controller method and expects you to set permissions based on user attributes you define. CanCan doesn’t provide default user attributes such as user roles; you must implement this outside of CanCan. There are many ways to <a href="https://github.com/ryanb/cancan/wiki/Role-Based-Authorization">implement role-based authorization</a> for use with CanCan. For this example, we use Florent Monbillard’s <a href="https://github.com/EppO/rolify">Rolify</a> gem to create a Role model, add methods to a User model, and generate a migration for a roles table.</p>
<h3>Set Up CanCan</h3>
<p>CanCan provides a Rails generator to create the CanCan <code>Ability</code> class. Run the generator to create the file <strong>app/models/ability.rb</strong>:</p>
<pre>
$ rails generate cancan:ability
</pre>
<p>Edit the file <strong>app/models/ability.rb</strong> to define a simple rule for granting permission to an administrator to access any page:</p>
<pre>
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :admin
can :manage, :all
end
end
end
</pre>
<p>Rules defined in the <code>Ability</code> class can become quite complex. See the CanCan wiki <a href="https://github.com/ryanb/cancan/wiki/defining-abilities">Defining Abilities</a> for details.</p>
<p>Note that the <code>user.has_role?</code> method doesn’t yet exist. We’ll add the method when we set up Rolify.</p>
<h3>Configure CanCan Exception Handling</h3>
<p>If user authorization fails, a <code>CanCan::AccessDenied</code> exception will be raised. See the CanCan wiki <a href="https://github.com/ryanb/cancan/wiki/exception-handling">Exception Handling</a> for ways to handle authorization exceptions.</p>
<p>For this example, we’ll handle the <code>CanCan::AccessDenied</code> exception in the ApplicationController. We’ll set an error message and redirect to the home page. Modify the file <strong>app/controllers/application_controller.rb</strong> like this:</p>
<pre>
class ApplicationController &lt; ActionController::Base
protect_from_forgery
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_path, :alert =&gt; exception.message
end
end
</pre>
<h3>Set Up User Roles</h3>
<p>We’ll use the <a href="https://github.com/EppO/rolify">Rolify</a> gem to implement user roles. Rolify provides a Rails generator to create a Role model, add methods to a User model, and generate a migration for a roles table. Run the command:</p>
<pre>
$ rails generate rolify:role
</pre>
<p>If you’re using Mongoid with the MongoDB datastore, add parameters to the command:</p>
<pre>
$ rails generate rolify:role Role User mongoid
</pre>
<p>The generator will insert a <code>rolify</code> method in <strong>app/models/users.rb</strong> and it will create several files:</p>
<ul>
<li><strong>app/models/role.rb</strong></li>
<li><strong>config/initializers/rolify.rb</strong></li>
<li><strong>db/migrate/…rolify_create_roles.rb</strong></li>
</ul><p>The <strong>app/models/role.rb</strong> looks like this:</p>
<pre>
class Role &lt; ActiveRecord::Base
has_and_belongs_to_many :users, :join_table =&gt; :users_roles
belongs_to :resource, :polymorphic =&gt; true
end
</pre>
<p>These few steps with CanCan and Rolify implement role-based authorization in our application. We’ll use the authorization options provided by CanCan and Rolify when we add an administrative page with corresponding links.</p>
<h2>Customize the Application</h2>
<p><em>The “Customize the Application” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<h3>Enable Users to Have Names</h3>
<p>By default, Devise uses an email address to identify users. We’ll add a “name” attribute as well. Your application may not require a user to provide a name. But showing you how to add a name will help you see what you need to do if you decide to make changes to the default Devise user model.</p>
<p>Devise created a migration file to establish the schema for the SQLite database with a migration file named something like <strong>db/migrate/xxxxxxx_devise_create_users.rb</strong>. We won’t modify the migration file. Instead we’ll add an additional migration that adds the “name” field to the User record.</p>
<pre>
rails generate migration AddNameToUsers name:string
</pre>
<p>Run the migration and prepare the test database to pick up the “name” field:</p>
<pre>
$ bundle exec rake db:migrate
$ bundle exec rake db:test:prepare
</pre>
<p>If you wish, you can modify the user model to validate the presence and uniqueness of the “name” attribute. Modify the file <strong>app/models/user.rb</strong> and add:</p>
<pre>
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive =&gt; false
</pre>
<p>This will allow users to be created (or edited) with a name attribute. When a user is created, a name and email address must be present and must be unique (not used before). Note that Devise (by default) will check that the email address and password are not blank and that the email address is unique.</p>
<p>You’ll also want to prevent malicious hackers from creating fake web forms that would allow changing of passwords through the mass-assignment operations of update_attributes(attrs) and new(attrs). Devise already added this to the <strong>models/user.rb</strong> file:</p>
<pre>
attr_accessible :email, :password, :password_confirmation, :remember_me
</pre>
<p>but you’ll need to add the “name” attribute:</p>
<pre>
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
</pre>
<p>If you’ve chosen to create the application with the Devise Confirmable module, also add <code>:confirmed_at</code>:</p>
<pre>
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :confirmed_at
</pre>
<h4 id="registration-views">Create Customized Views for User Registration (<span class="caps">ERB</span>)</h4>
<p>Devise provides a controller and views for registering users. It is called the “registerable” module. The controller and views are hidden in the Devise gem so we don’t need to create anything. However, because we want our users to provide a name when registering, we will create custom views for creating and editing a user. Our custom views will override the Devise gem defaults.</p>
<p>First, to copy all the default Devise views to your application, run</p>
<p><code>rails generate devise:views</code></p>
<p>This will generate a set of views in the directory <strong>app/views/devise/</strong>.</p>
<p>Next, modify the views to create and edit users.</p>
<p>Add the following code to each file:</p>
<p><strong>app/views/devise/registrations/edit.html.erb</strong></p>
<pre>
&lt;p&gt;&lt;%= f.label :name %&gt;&lt;br /&gt;
&lt;%= f.text_field :name %&gt;&lt;/p&gt;
</pre>
<p><strong>app/views/devise/registrations/new.html.erb</strong></p>
<pre>
&lt;p&gt;&lt;%= f.label :name %&gt;&lt;br /&gt;
&lt;%= f.text_field :name %&gt;&lt;/p&gt;
</pre>
<p>We do not need to add a controller with methods to create a new user or edit or delete a user. We use the existing “registerable” module from Devise which provides a controller with methods to create, edit or delete a user.</p>
<p>Note that Devise’s default behaviour allows any logged-in user to edit or delete his or her own record (but no one else’s). When you access the edit page you are editing just your info, and not info of other users.</p>
<h3>Create Customized Views for User Registration (Haml)</h3>
<p>If you are using Haml, Devise does not generate views for Haml (it did before Devise 1.2; see <a href="https://github.com/plataformatec/devise/issues/878">Devise issue 878</a>). See <a href="https://github.com/plataformatec/devise/wiki/How-To:-Create-Haml-and-Slim-Views">How To Create Haml and Slim Views</a> from the Devise wiki.</p>
<p>If you are using Haml, you can generate the <span class="caps">ERB</span> files using <code>rails generate devise:views</code> and then convert them using the online tool <a href="http://html2haml.heroku.com/">Html2Haml</a>. You’ll need to remove the <strong>.erb</strong> files and replace them with <strong>app/views/devise/registrations/edit.html.haml</strong> and <strong>app/views/devise/registrations/new.html.haml</strong>.</p>
<h2>Create a Home Page</h2>
<p><em>The “Create a Home Page” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<h3>Remove the Default Home Page</h3>
<p>Delete the default home page from your application:</p>
<p><code>$ rm public/index.html</code></p>
<h3>Create a Home Controller and View</h3>
<p>Create the first page of the application. Use the Rails generate command to create a “home” controller and a “views/home/index” page. Specify <code>--no-controller-specs</code> to avoid overwriting the RSpec files you’ve already downloaded.</p>
<p><code>$ rails generate controller home index --no-controller-specs</code></p>
<p>If you’re using the default template engine, you’ll find an <strong>erb</strong> file with placeholder content:</p>
<p><strong>app/views/home/index.html.erb</strong></p>
<p>Next, set a route to your home page. Edit the file <strong>config/routes.rb</strong> and replace:</p>
<p><code>get "home/index"</code></p>
<p>with</p>
<pre>
authenticated :user do
root :to =&gt; 'home#index'
end
root :to =&gt; "home#index"
</pre>
<p>If you examine this code, you’ll see that authenticated users (those who have an account and are logged in) will see the home/index page as the application root (or home) page. And all other users (those who don’t have an account or who are not logged in) will see the same home page. The redundancy serves a didactic purpose: If you decide you want users to see a different page when they log in, you now know exactly where to change it.</p>
<p>By default, Devise will redirect to the root_path after successful sign in or sign out. It is easy to change the root_path as shown in the <strong>config/routes.rb</strong> file. Alternatively, you can override the Devise methods <code>after_sign_in_path_for</code> and <code>after_sign_out_path_for</code> as described in the Devise wiki article <a href="https://github.com/plataformatec/devise/wiki/How-To%3A-Redirect-to-a-specific-page-on-successful-sign-in-out">How To Redirect to a Specific Page</a>.</p>
<h3>Test the App</h3>
<p>You can check that your app runs properly by entering the command</p>
<p><code>$ rails server</code></p>
<p>To see your application in action, open a browser window and navigate to <a href="http://localhost:3000">http://localhost:3000/</a>. You should see your new home page.</p>
<p>Stop the server with Control-C.</p>
<h2>Display Users on the Home Page</h2>
<p><em>The “Display Users on the Home Page” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<p>Modify the file <strong>app/controllers/home_controller.rb</strong> and add:</p>
<pre>
def index
@users = User.all
end
</pre>
<p>Modify the file <strong>app/views/home/index.html.erb</strong> and add:</p>
<pre>
&lt;h3&gt;Home&lt;/h3&gt;
&lt;% @users.each do |user| %&gt;
&lt;p&gt;User: &lt;%= user.name %&gt; &lt;/p&gt;
&lt;% end %&gt;
</pre>
<p>This code is not appropriate for deployment in a real application. You likely will not want to display a list of users on the home page. However, it is convenient for our example.</p>
<h2>Create a Default User</h2>
<h3>Set Up a Database Seed File</h3>
<p><em>The “Set Up a Database Seed File” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is very similar. Here we add code to make the first user an administrator.</em></p>
<p>You’ll want to set up a default user so you can test the app. Modify the file <strong>db/seeds.rb</strong> by adding:</p>
<pre>
puts 'SETTING UP DEFAULT USER LOGIN'
user = User.create! :name =&gt; 'First User', :email =&gt; 'user@example.com', :password =&gt; 'please', :password_confirmation =&gt; 'please'
puts 'New user created: ' &lt;&lt; user.name
user2 = User.create! :name =&gt; 'Second User', :email =&gt; 'user2@example.com', :password =&gt; 'please', :password_confirmation =&gt; 'please'
puts 'New user created: ' &lt;&lt; user2.name
user.add_role :admin
</pre>
<p>If you’ve chosen to create the application with the Devise Confirmable module, add the field <code>confirmed_at</code>:</p>
<pre>
puts 'SETTING UP DEFAULT USER LOGIN'
user = User.create! :name =&gt; 'First User', :email =&gt; 'user@example.com', :password =&gt; 'please', :password_confirmation =&gt; 'please', :confirmed_at =&gt; DateTime.now
puts 'New user created: ' &lt;&lt; user.name
user2 = User.create! :name =&gt; 'Second User', :email =&gt; 'user2@example.com', :password =&gt; 'please', :password_confirmation =&gt; 'please', :confirmed_at =&gt; DateTime.now
puts 'New user created: ' &lt;&lt; user2.name
user.add_role :admin
</pre>
<p>You can change the values for name, email, and password as you wish.</p>
<h3>Seed the Database</h3>
<p>Add the default user to the database by running the command:</p>
<p><code>$ bundle exec rake db:seed</code></p>
<p>If you need to, you can run <code>$ bundle exec rake db:reset</code> to drop and then recreate the database using your seeds.rb file.</p>
<p>If the task fails with “Validation failed: Name can’t be blank” you should check that the file <strong>models/user.rb</strong> allows the “name” attribute to be mass updated:</p>
<pre>
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
</pre>
<h3>Test the App</h3>
<p>At this point, you may want to know if the default user has been saved to the database.</p>
<p>You can check that your app runs properly by entering the command</p>
<p><code>$ rails server</code></p>
<p>To see your application in action, open a browser window and navigate to <a href="http://localhost:3000">http://localhost:3000/</a>. You should see your new home page.</p>
<p>Stop the server with Control-C.</p>
<h2>Add Links to Users on the Home Page</h2>
<p><em>The “Add Links to Users on the Home Page” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is identical.</em></p>
<p>You’ve already modified the file <strong>app/controllers/home_controller.rb</strong> to include this:</p>
<pre>
def index
@users = User.all
end
</pre>
<p>Now modify the file <strong>app/views/home/index.html.erb</strong> to look like this:</p>
<pre>
&lt;h3&gt;Home&lt;/h3&gt;
&lt;% @users.each do |user| %&gt;
&lt;p&gt;User: &lt;%=link_to user.name, user %&gt;&lt;/p&gt;
&lt;% end %&gt;
</pre>
<p>This code is not appropriate for deployment in a real application. You likely will not want to display a list of users on the home page. However, it is convenient for our example.</p>
<p>The links to the user’s profile page will not yet work; in the next section we’ll create a users controller, routes, and views.</p>
<h2>Set Up the Users Controller, Routes, and Views</h2>
<p><em>The “Set Up the Users Controller, Views, and Routes” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is very similar. Here we set up the UsersController to demonstrate use of authorization in a later step.</em></p>
<h3>Create a Users Controller</h3>
<p>Use the Rails generate command to create a “users” controller and a “views/user/show” page. You can specify <code>--no-controller-specs</code> if you’ve already downloaded RSpec files for the example application.</p>
<p><code>$ rails generate controller users index show --no-controller-specs</code></p>
<p>Note that “users” is plural when you create the controller.</p>
<h3>Set Up the Users Routes</h3>
<p>The file <strong>config/routes.rb</strong> has already been modified to include:</p>
<pre>
get "users/index"
get "users/show"
</pre>
<p>Remove that and change the routes to:</p>
<pre>
root :to =&gt; "home#index"
devise_for :users
resources :users, :only =&gt; [:show, :index]
</pre>
<p>Important note: The <code>devise_for :users</code> route must be placed above <code>resources :users, :only =&gt; [:show, :index]</code>.</p>
<h3>Set Up the Users#Show Page</h3>
<p>Modify the file <strong>app/views/users/show.html.erb</strong> and add:</p>
<pre>
&lt;p&gt;User: &lt;%= @user.name %&gt;&lt;/p&gt;
&lt;p&gt;Email: &lt;%= @user.email if @user.email %&gt;&lt;/p&gt;
</pre>
<p>In a typical application, this page might provide additional details about the user’s account.</p>
<h3>Set Up the Users#Index Page</h3>
<p>For the purposes of our example, this page will be accessible only to administrators. It will display a list of all users of the application.</p>
<p>Modify the file <strong>app/views/users/index.html.erb</strong> and add:</p>
<pre>
&lt;ul class="users"&gt;
&lt;% @users.each do |user| %&gt;
&lt;li&gt;
&lt;%= link_to user.name, user %&gt; signed up &lt;%= user.created_at.to_date %&gt;
&lt;/li&gt;
&lt;% end %&gt;
&lt;/ul&gt;
</pre>
<p>We want to restrict access to this page, the <strong>Users#index</strong> page at <a href="http://localhost:3000/users">http://localhost:3000/users</a>. In the next section, we will set up authorization so the page is accessible only to administrators.</p>
<h2>Set Up a Demonstration of CanCan</h2>
<p><em>The “Set Up a Demonstration of Devise” step in the <a href="https://github.com/RailsApps/rails3-devise-rspec-cucumber">rails3-devise-rspec-cucumber</a> tutorial is very similar. Here we add code to limit access to the <code>index</code> method of the UsersController.</em></p>
<p>You’ll want to see how CanCan is used to limit access to only the administrator.</p>
<h3>First Authorization Example: Users Controller with CanCan “@authorize!”</h3>
<p>Modify the file <strong>app/controllers/users_controller.rb</strong> like this:</p>
<pre>
class UsersController &lt; ApplicationController
before_filter :authenticate_user!
def index
authorize! :index, @user, :message =&gt; 'Not authorized as an administrator.'
@users = User.all
end
def show
@user = User.find(params[:id])
end
end
</pre>
<p>Only one line of code is needed to limit access to the <strong>Users#index</strong> page at<br><a href="http://localhost:3000/users">http://localhost:3000/users</a>:</p>
<pre>
authorize! :index, @user, :message =&gt; 'Not authorized as an administrator.'
</pre>
<p>The CanCan <code>authorize!</code> method will check the CanCan <code>Ability</code> class definition to determine if the user has permission to execute the <code>index</code> method. We’ve previously set a rule in the <code>Ability</code> class definition that gives a user in an administrator role the ability to execute all methods:</p>
<pre>
if user.has_role? :admin
can :manage, :all
end
</pre>
<p>No rule is present for other users, so by default, other users are restricted from executing the <code>index</code> method.</p>
<p>This approach is the most obvious way to implement authorization using CanCan. However, CanCan offers convenience methods that can eliminate superfluous controller code in some applications. The next example shows how to use CanCan convenience methods to reduce the amount of code in your controllers.</p>
<h3>Second Authorization Example: Users Controller with CanCan “load_and_authorize_resource”</h3>
<p>CanCan provides a convenience method <code>authorize_resource</code> that applies the <code>authorize!</code> method to every action in the controller. Another convenience method <code>load_resource</code> queries the database and loads the resources required by each action (for example, <code>users = User.all</code> for the <code>index</code> action). A third convenience method combines the two as <code>load_and_authorize_resource</code>.</p>
<p>Using <code>load_and_authorize_resource</code>, you can set up the file <strong>app/controllers/users_controller.rb</strong> like this:</p>
<pre>
class UsersController &lt; ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource :only =&gt; :index
def show
@user = User.find(params[:id])
end
end
</pre>
<p>The <code>index</code> action does not need to be declared because Rails provides it by default.</p>
<p>If a non-administrator tries to view the at <a href="http://localhost:3000/users">http://localhost:3000/users</a> he or she will be redirected to the home page (as specified by the <code>rescue_from CanCan::AccessDenied</code> method in the ApplicationController) and will see CanCan’s generic exception message, “You are not authorized to access this page.” You can customize the exception message in the ApplicationController, if you wish.</p>
<p>Some developers will like this approach; others will feel it dries up code at the expense of introducing layers of black magic. If you prefer a more explicit approach, the next example shows how to implement simple role-based authorization without using CanCan at all.</p>
<h3>Third Authorization Example: Users Controller without CanCan</h3>
<p>The purported benefit of using CanCan is the advantage of maintaining authorization rules in one location, the <code>Ability</code> class. This may be a matter of taste; you may prefer to confine authorization code to only the controllers that need it.</p>
<p>Here is an example of limiting access to the <strong>Users#index</strong> page using only methods provided by the <a href="https://github.com/EppO/rolify">Rolify</a> gem. CanCan is not used.</p>
<pre>
class UsersController &lt; ApplicationController
before_filter :authenticate_user!
before_filter :only_allow_admin, :only =&gt; [ :index ]
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
private
def only_allow_admin
redirect_to root_path, :alert =&gt; 'Not authorized as an administrator.' unless current_user.has_role? :admin
end
end
</pre>
<p>If multiple controllers will use the <code>only_allow_admin</code> method, it can be moved to the ApplicationController so all controllers will inherit the method.</p>
<p>In contrast to CanCan, all the authorization logic is defined in the controller. For a small application, this approach is simpler and less confusing. You may find this approach preferable to using CanCan, if your application only requires simple role-based authorization. However, for a large or complex application with multiple roles and many constrained activities, CanCan offers better <a href="http://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a>.</p>
<h2>Create an Application Layout</h2>
<p>Rails will use the layout defined in the file <strong>app/views/layouts/application.html.erb</strong> as a default for rendering any page. If you are using Haml, the file will be <strong>app/views/layouts/application.html.haml</strong>.</p>
<p>You’ll want to add navigation links, include flash messages for errors and notifications, and apply <span class="caps">CSS</span> styling.</p>
<p>This tutorial shows code using <span class="caps">ERB</span>, the default Rails templating language. If you prefer to use Haml, see the detailed guide <a href="http://railsapps.github.com/rails-default-application-layout.html">Rails Default Application Layout for HTML5</a>.</p>
<h3>Navigation Links</h3>
<p>You’ll likely need navigation links on every page of your web application. You’ll want a link for Home. You’ll want links for Login, Logout, and Sign Up. And a user who is an administrator should see a link for Admin.</p>
<p>You can add navigation links directly to your application layout file but many developers prefer to create a <a href="http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials">partial template</a> – a “partial” – to better organize the default application layout.</p>
<p>Create the file <strong>app/views/layouts/_navigation.html.erb</strong> for the navigation links:</p>
<pre>
&lt;%= link_to "Rails3 Bootstrap Devise Cancan", root_path, :class =&gt; 'brand' %&gt;
&lt;ul class="nav"&gt;
&lt;% if user_signed_in? %&gt;
&lt;li&gt;
&lt;%= link_to('Logout', destroy_user_session_path, :method=&gt;'delete') %&gt;
&lt;/li&gt;
&lt;% else %&gt;
&lt;li&gt;
&lt;%= link_to('Login', new_user_session_path) %&gt;
&lt;/li&gt;
&lt;% end %&gt;
&lt;% if user_signed_in? %&gt;
&lt;li&gt;
&lt;%= link_to('Edit account', edit_user_registration_path) %&gt;
&lt;/li&gt;
&lt;% if current_user.has_role? :admin %&gt;
&lt;li&gt;
&lt;%= link_to('Admin', users_path) %&gt;
&lt;/li&gt;
&lt;% end %&gt;
&lt;% else %&gt;
&lt;li&gt;
&lt;%= link_to('Sign up', new_user_registration_path) %&gt;
&lt;/li&gt;
&lt;% end %&gt;
&lt;/ul&gt;
</pre>
<p>Notice the condition <code>&lt;% if current_user.has_role? :admin %&gt;</code> that uses a <code>has_role?</code> method provided by the Rolify gem. The Admin link will display only if the user is an administrator.</p>
<h3>Flash Messages</h3>
<p>Rails provides a standard convention to display alerts (including error messages) and other notices (including success messages), called Rails “flash messages” (as in “flash memory”, not to be confused with the “Adobe Flash” proprietary web development platform).</p>
<p>You can include code to display flash messages directly in your application layout file or you can create a partial.</p>
<p>Create a partial for flash messages in <strong>app/views/layouts/_messages.html.erb</strong> like this:</p>
<pre>
&lt;% flash.each do |name, msg| %&gt;
&lt;div class="alert alert-&lt;%= name == :notice ? "success" : "error" %&gt;"&gt;
&lt;a class="close" data-dismiss="alert"&gt;&amp;#215;&lt;/a&gt;
&lt;%= content_tag :div, msg, :id =&gt; "flash_#{name}" if msg.is_a?(String) %&gt;
&lt;/div&gt;
&lt;% end %&gt;
</pre>
<p>Rails uses <code>:notice</code> and <code>:alert</code> as flash message keys. Twitter Bootstrap provides a base class <code>.alert</code> with additional classes <code>.alert-success</code> and <code>.alert-error</code> (see the <a href="http://twitter.github.com/bootstrap/components.html#alerts">Bootstrap documentation on alerts</a>). A bit of parsing is required to get a Rails “notice” message to be styled with the Twitter Bootstrap “alert-success” style. Any other message, including a Rails “alert” message, will be styled with the Twitter Bootstrap “alert-error” style.</p>
<p>Twitter Bootstrap provides a jQuery plugin named bootstrap-alert that makes it easy to dismiss flash messages with a click. The data-dismiss property displays an “x” that enables the close functionality. Note that Twitter Bootstrap uses the <span class="caps">HTML</span> entity “&amp;#215;” instead of the keyboard letter “x”.</p>
<p>By default, Twitter Bootstrap applies a green background to <code>.alert-success</code> and a red background to <code>.alert-error</code>. Twitter Bootstrap provides a third class <code>.alert-info</code> with a blue background. With a little hacking, it’s possible to create a Rails flash message with a custom name, such as <code>:info</code>, that will display with the Bootstrap <code>.alert-info</code> class. However, it’s wise to stick with the Rails convention of using only “alert” and “notice.”</p>
<h3>
<span class="caps">CSS</span> Styling with <span class="caps">SASS</span>
</h3>
<p>It’s a good idea to rename the <strong>app/assets/stylesheets/application.css</strong> file as <strong>app/assets/stylesheets/application.css.scss</strong>.</p>
<p>This will allow you to use the advantages of the <span class="caps">SASS</span> syntax and features for your application stylesheet. For more on the advantages of <span class="caps">SASS</span> and how to use it, see the <a href="http://railscasts.com/episodes/268-sass-basics"><span class="caps">SASS</span> Basics</a> RailsCast from Ryan Bates.</p>
<h3>
<span class="caps">CSS</span> Styling with Twitter Bootstrap</h3>
<p><a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a> and other <span class="caps">CSS</span> front-end frameworks (such as <a href="http://foundation.zurb.com/">Zurb Foundation</a>) are toolkits that provide the kind of structure and convention that make Rails popular for server-side (“back-end”) development. You can use Twitter Bootstrap to quickly add attractive <span class="caps">CSS</span> styling to your application. If you’ve generated your app from an application template in the <a href="https://github.com/RailsApps/rails3-application-templates">RailsApps Application Templates</a> repository, the script will offer to install Twitter Bootstrap or other <span class="caps">CSS</span> front-end frameworks and set up your default application layout accordingly.</p>
<p>Several options are available for installing Twitter Bootstrap in a Rails application. Twitter Bootstrap can be installed using either its native <a href="http://lesscss.org/"><span class="caps">LESS</span> <span class="caps">CSS</span></a> language or the <a href="http://sass-lang.com/"><span class="caps">SASS</span></a> language that is the default for <span class="caps">CSS</span> files in Rails. See the article <a href="http://rubysource.com/twitter-bootstrap-less-and-sass-understanding-your-options-for-rails-3-1/">Twitter Bootstrap, Less, and Sass: Understanding Your Options for Rails 3.1</a>. <span class="caps">SASS</span> is a default for <span class="caps">CSS</span> development in Rails so I recommend you install Thomas McDonald’s <a href="https://github.com/thomas-mcdonald/bootstrap-sass">bootstrap-sass</a> gem.</p>
<p>In your <strong>Gemfile</strong>, you’ve already added:</p>
<pre>
gem 'bootstrap-sass'
</pre>
<p>and previously run <code>$ bundle install</code>.</p>
<p>Include the Twitter Bootstrap Javascript files by modifying the file <strong>app/assets/javascripts/application.js</strong>:</p>
<pre>
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require_tree .
</pre>
<p>Next, import the Twitter Bootstrap <span class="caps">CSS</span> files. You can modify the <strong>app/assets/stylesheets/application.css.scss</strong> file to import Bootstrap. However, I recommend adding a new file <strong>app/assets/stylesheets/bootstrap_and_overrides.css.scss</strong> file. You may wish to modify the Twitter Bootstrap <span class="caps">CSS</span> rules; you can do so in the <strong>application.css.scss</strong> file but placing changes to Twitter Bootstrap <span class="caps">CSS</span> rules in the <strong>bootstrap_and_overrides.css.scss</strong> file will keep your <span class="caps">CSS</span> better organized.</p>
<p>The file <strong>app/assets/stylesheets/bootstrap_and_overrides.css.scss</strong> is automatically included and compiled into your Rails application.css file by the <code>*= require_tree .</code> statement in the <strong>app/assets/stylesheets/application.css.scss</strong> file.</p>
<p>Add the file <strong>app/assets/stylesheets/bootstrap_and_overrides.css.scss</strong>:</p>
<pre>
@import "bootstrap";
body { padding-top: 60px; }
@import "bootstrap-responsive";
</pre>
<p>The file will import both basic Bootstrap <span class="caps">CSS</span> rules and the Bootstrap rules for responsive design (allowing the layout to resize for various devices and secreen sizes).</p>
<p>The <span class="caps">CSS</span> rule <code>body { padding-top: 60px; }</code> applies an additional <span class="caps">CSS</span> rule to accommodate the “Bootstrap black bar” heading created by the <code>navbar-fixed-top class</code> in the <code>header</code> tag in the layout below.</p>
<p>Finally, to provide an example of adding a <span class="caps">CSS</span> rule that will be used on every page of your application, the following code creates a nice gray box as a background to page content.</p>
<p>Add this to your <strong>app/assets/stylesheets/application.css.scss</strong> file for a gray background:</p>
<pre>
.content {
background-color: #eee;
padding: 20px;
margin: 0 -20px; /* negative indent the amount of the padding to maintain the grid system */
-webkit-border-radius: 0 0 6px 6px;
-moz-border-radius: 0 0 6px 6px;
border-radius: 0 0 6px 6px;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15);
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.15);
box-shadow: 0 1px 2px rgba(0,0,0,.15);
}
</pre>
<h3>Default Application Layout with Twitter Bootstrap</h3>
<p>Generating a new Rails application with the <code>rails new</code> command will create a default application layout in the file <strong>app/views/layouts/application.html.erb</strong>. Modify the file to add navigation links, include flash messages, and apply <span class="caps">CSS</span> styling. Twitter Bootstrap provides additional elements for a more complex page layout.</p>
<p>Use the code below to incorporate recommendations from the article <a href="http://railsapps.github.com/rails-html5-boilerplate.html">HTML5 Boilerplate for Rails Developers</a>.</p>
<p>Replace the contents of the file <strong>app/views/layouts/application.html.erb</strong> with this:</p>
<pre>
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
&lt;title&gt;&lt;%= content_for?(:title) ? yield(:title) : "Myapp" %&gt;&lt;/title&gt;
&lt;meta name="description" content=""&gt;
&lt;meta name="author" content=""&gt;
&lt;%= stylesheet_link_tag "application", :media =&gt; "all" %&gt;
&lt;%= javascript_include_tag "application" %&gt;
&lt;%= csrf_meta_tags %&gt;
&lt;%= yield(:head) %&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header class="navbar navbar-fixed-top"&gt;
&lt;nav class="navbar-inner"&gt;
&lt;div class="container"&gt;
&lt;%= render 'layouts/navigation' %&gt;
&lt;/div&gt;
&lt;/nav&gt;
&lt;/header&gt;
&lt;div id="main" role="main"&gt;
&lt;div class="container"&gt;
&lt;div class="content"&gt;
&lt;div class="row"&gt;
&lt;div class="span12"&gt;
&lt;%= render 'layouts/messages' %&gt;
&lt;%= yield %&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;footer&gt;
&lt;/footer&gt;
&lt;/div&gt;
&lt;/div&gt; &lt;!--! end of .container --&gt;
&lt;/div&gt; &lt;!--! end of #main --&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<h3>Options and Improvements</h3>
<p>Your default application layout defines the look-and-feel of your application. You now have the basics with navigation links, messages for alerts and notices, and <span class="caps">CSS</span> styling using Twitter Bootstrap.</p>
<p>There’s much more you can do. For an advanced example, see the RailsApp <a href="https://github.com/RailsApps/rails-prelaunch-signup">rails-prelaunch-signup</a> example app. The <a href="http://railsapps.github.com/tutorial-rails-prelaunch-signup.html">rails-prelaunch-signup tutorial</a> shows how you can use Twitter Bootstrap to add a modal window and <span class="caps">AJAX</span> for a “sign up” form for a “Web 2.0” application. When the visitor submits the form, the modal window changes to display a “thank you” message (or an error message) without a page refresh.</p>
<h2>Cleanup</h2>
<p>Several unneeded files are generated in the process of creating a new Rails application.</p>
<p>Additionally, you may want to prevent search engines from indexing your website if you’ve deployed it publicly while still in development.</p>
<p>See instructions for <a href="http://railsapps.github.com/rails-cleanup.html">cleaning up unneeded files in Rails and banning spiders</a>.</p>
<h2>Test the App</h2>
<p>You can check that your app runs properly by entering the command</p>
<p><code>$ rails server</code></p>
<p>To see your application in action, open a browser window and navigate to <a href="http://localhost:3000">http://localhost:3000/</a>. You should see the default user listed on the home page. When you click on the user’s name, you should be required to log in before seeing the user’s detail page.</p>
<p>To sign in as the first user (the administrator), (unless you’ve changed it) use</p>
<ul>
<li>email: user@example.com</li>
<li>password: please</li>
</ul><p>You’ll see a navigation link for Admin. Clicking the link will display a page with a list of users at<br><a href="http://localhost:3000/users">http://localhost:3000/users</a>.</p>
<p>To sign in as the second user, (unless you’ve changed it) use</p>
<ul>
<li>email: user2@example.com</li>
<li>password: please</li>
</ul><p>The second user will not see the Admin navigation link and will not be able to access the page at<br><a href="http://localhost:3000/users">http://localhost:3000/users</a>.</p>
<p>Stop the server with Control-C.</p>
<h2>Deploy to Heroku</h2>
<p>Heroku provides low cost, easily configured Rails application hosting. For your convenience, see <a href="http://railsapps.github.com/rails-heroku-tutorial.html">Tutorial: Rails on Heroku</a>.</p>
<h2>Conclusion</h2>
<p>This concludes the tutorial for creating a Ruby on Rails web application that uses Devise and adds <a href="https://github.com/ryanb/cancan">CanCan</a> and <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a>.</p>
<h3>Credits</h3>
<p>Daniel Kehoe implemented the application and wrote the tutorial.</p>
<p>Was this useful to you? Follow <a href="http://twitter.com/rails_apps">rails_apps</a> on Twitter and tweet some praise. I’d love to know you were helped out by the tutorial.</p>
<p>Any issues? Please create an <a href="http://github.com/RailsApps/rails3-bootstrap-devise-cancan/issues">Issue</a> on GitHub.</p>
</div><!-- class="content" -->
<div class="comments">
<div class="content wikistyle gollum">
<h2>Comments and Issues</h2>
</div>
<p>Is this helpful? Please add a comment below. Your encouragement fuels the project.</p>
<p>Did you find an error? Or couldn't get something to work? For the example apps and tutorials, please create a GitHub issue in the repository for the example app. Creating a GitHub issue is the best way to make sure a problem is investigated and fixed.</p>
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'railsapps'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</div><!-- class="comments" -->
<div class="footer row">
<div class="span4">
<h3>Credits</h3>
<p><a href="http://danielkehoe.com/">Daniel Kehoe</a> initiated the <a href="http://railsapps.github.com/">RailsApps Project</a>. Thanks to all the users and contributors.</p>
</div>
<div class="span4">
<h3>Wiki</h3>
<p>Corrections? Additions? You can edit this page <a href="https://github.com/RailsApps/railsapps.github.com/wiki/_pages">on the wiki</a>.</p>
</div>
<div class="span4">
<h3>Last edit</h3>
<p>by <b>Daniel Kehoe</b>, 2012-07-20 23:08:42</p>
</div>
</div>
</div>
</body>
</html>