Ruby on Rails Tutorial: Learn From Scratch

banner_Ruby

By Jordan Hudgens for Udemy

Looking for more than a guide? Take Jordan’s comprehensive Ruby on Rails course.

Note: This post is part of our “Getting Started” series of free text tutorials on some of our most popular course topics.

To jump to a specific section, click the table of contents below:

Setting up Your Environment

Installing Rails
Installing Postgres
Installing RVM

Creating a Rails Application

Creating the application
Options for application creation
Database options and creation
Analyzing the file structure

Scaffolding the application

Scaffolding vs. model/controller generation vs. building from scratch
What do scaffolds create?
Creating the first scaffold
Updating the database

Rails console

The purpose of the Rails console
How to run queries in the console
Running in sandbox mode
Creating records in the database from the console
Deleting records in the database from the console
Updating records in the database from the console

Rails Routing

What are RESTful routes?
Basic fundamentals of routing
Configuring routes

Updating the views

What are erb view files?
Syntax for erb files
Different options for views, namely Haml
Working with the Rails asset pipeline
Asset pipeline images
Asset pipeline CSS
Asset pipeline Javascript

Updating the controllers

The purpose of controllers
Antipatterns for controllers
Customizing queries in the controller

Working with the model files

The purpose of model files
The type of code that should go in model files
Creating model files that aren’t active record models
Adding custom scopes to models
Adding data defaults to a model file
Integrating validations
Integrating callbacks

Database changes

What is a database migration?
Different ways to change the database schema
Integrating foreign keys into migrations
Adding columns to a database table
Removing columns from a database table

Helpful Gems/libraries

What are Ruby Gems?
When should I use a Gem?
Carrierwave
Fog
dot-env
Devise
Pry
Smart Listing
Font Awesome
Bootstrap

Image uploads and management

Integrate gems to handle images
Securing config credentials
Integrate with the AWS S3 API
Managing uploads
How to display images with Carrierwave

Authentication

Devise installation
Customizing devise
Login process
Logout process
Editing user information

Deploying to the Web

Deployment options
Deploying to Heroku
Heroku addons
Setting up a scheduled task

Advanced development

Testing
Microservices
Gem development


Setting Up Your environment

Before we can start building out Rails applications, we first need to configure our system to work properly. It is typically discouraged to run Rails on a PC, so this tutorial will be geared towards Mac and Linux usage. If you have a PC, you can still follow along and you have a few different options to choose from:

– Installing a virtual box on your PC to run Ubuntu from – instructions here
– Using a cloud- based development environment, such as Nitrous. This is a great way to get up and running quickly and you can perform everything that you would want to do on a traditional Unix setup. You can sign up for a free account here to follow along. If you sign up for Nitrous, you will not need to follow the other steps below; their system generator does that all for you.

Installing Rails

The installation process for Rails is quite extensive, which is why I always recommend that students leverage pre-existing tools out there that will walk them through it. Follow the steps outlined at InstallRails and it will outline everything that is required for your specific operating system:

Installing Postgres

In addition to the Sqlite database, we will also be utilizing Postgres as a database engine. Many students have issues when installing Postgres, which is why I recommend multiple options in case one does not work for you.

The first option is to download the app itself. You can do it here:

If that does not work for you, then I would recommend utilizing Homebrew. If you do not have Homebrew installed on your machine, go here and follow the instructions:

Once you have Homebrew installed, follow these instructions for installing and managing Postgres:

Installing RVM

If you are on a Mac, your system ships with Ruby installed. However, if you are going to work on multiple applications, it is typically a good idea to have the ability to switch between Ruby versions. I utilize RVM to manage this process; for installing RVM, follow these instructions:

Creating a Rails Application

Creating the application

The first task that you will want to do is create the application itself. Open up your system’s terminal, navigate to the directory that you want to store the application in, and run the following command:

rails new tasker

This will generate the full application, including the configuration files, application controller, and directories for models, views, and controllers.

Options for application creation

For a shortcut, Rails gives a number of custom options that can be utilized to automatically configure the application. To find the full list of options, simply run:

rails new --help

A number of the options are rarely used; however, a few of them could be selected in every application. For example, I will typically set the default Database, bypass the built-in testing module, and skip some built-in functionality that I have found to cause issues with my development workflow. Below is a command that would create the application:

This accomplishes the following presets:
It sets Postgres as the database, instead of SQLite. I like using Postgres as the development database since I prefer having the same database utilized locally as used in production. There are a number of reasons why I take this approach – mainly because it has been my experience that Postgres is more strict than SQLite and there have been times when I had an application running perfectly on my local machine with SQLite, only to have it not work at all due to Postgres errors after pushing the application to a live web server, such as Heroku.

It skips the Minitest module, which is what Rails comes with by default. This is in my workflow since I typically will use RSpec for application testing. I prefer RSpec’s syntax and descriptive nature. By bypassing the Minitest module, it saves time later on and also makes for a cleaner code base. I have taken over legacy applications in the past and discovered that a previous developer had not removed Minitest and simply installed Rspec on top of that, which made for a confusing code analysis since it was not readily apparent which testing module was actually testing the application.

It skips the turbolinks integration. Turbolinks is a great tool that can help make a Rails application act like a single-page application. However, if the application is going to utilize a large number of custom JavaScript modules, Turbolinks can cause a number of confusing conflicts, which is why I will typically bypass it entirely. At RailsConf 2015, Rails creator David Heinemeier Hansson announced that there will be a number of improvements for Turbolinks in Rails 5, so I will be testing that out whenever version 5 is released, but for now I skip it for simplicity’s sake.

Database options and creation

After the application has been created, change into the application directory, running the following command:

cd tasker

Once inside the directory, the first task that needs to be completed is creating the database and database schema files. This can be done by running:

rake db:create:all
rake db:migrate

The Rails API allows for a large number of database tasks. Below is a comprehensive list of commands along with what they do:

db:create creates the database for the current environment
db:create:all creates the databases for all environments
db:drop drops the database for the current environment
db:drop:all drops the databases for all environments
db:migrate runs migrations for the current environment that have not run yet
db:migrate:up runs one specific migration
db:migrate:down rolls back one specific migration
db:migrate:status shows current migration status
db:rollback rolls back the last migration
db:forward advances the current schema version to the next one
db:seed runs the db/seed.rb file
db:schema:load loads the schema into the current environment's database
db:schema:dump dumps the current environment's schema (and seems to create the db as well)
db:setup runs db:schema:load, db:seed
db:reset runs db:drop db:setup
db:migrate:redo runs (db:migrate:down db:migrate:up) or (db:rollback db:migrate:migrate) depending on the specified migration
db:migrate:reset runs db:drop db:create db:migrate

Analyzing the file structure

Generating a Rails application does quite a bit of work, as you can see by reviewing the files created. The file structure of the application contains the following directories:

app – contains the models, views, and controllers, along with the the rest of the core functionality of the application.

bin – some built-in Rails tasks that you most likely will never have to work with

config – the config directory manages a number of settings that control the default behavior, including: the environment settings, a set of modules that are initialized when the application starts, the ability to set language values, the application settings, the database settings, the application routes, and lastly the secret key base.

db – within the db directory you will find the database schema file that lists the database table, their columns and the column’s associated data types. The db directory also contains the seeds.rb file, which lets you create some data that can be utilized in the application. This is a great way to quickly integrate data in the application without having to manually add records through a web form element.

lib – while many developers could build full applications without ever entering the lib directory, you will discover that it can be incredibly helpful. The lib/tasks directory is where custom rake tasks are created. You have already used a built-in rake task when you ran the database creation and migration tasks; however, creating custom rake tasks can be very helpful and sometimes necessary. An example of a rake task I have created recently was a rake task that I had the server run in the background that called an outside API and synced the API data into the application’s database.

log – within the log directory you will discover the application logs. This can be helpful for debugging purposes, but for production application I will typically use a outside service since they can offer more advanced services such as querying and alerts.

public – this directory contains some of the custom error pages, such as 404 errors, along with the robots.txt file which will let developers control how search engines index the application on the web.

test – if you did not bypass the Minitest installation, Rails will install the test directory; if you added the option of –skip-test-unit this test directory will not be included.

tmp – this is where the temporary items are stored and is rarely accessed by developers.

vendor – in earlier versions of Rails the public folder used to be where developers could place assets, such as CSS styles and JavaScript code, but in Rails 4+ the Rails asset pipeline responsibilities were moved to the app/assets directory. In Rails 4+ the vendor directory can be utilized to manage outside JavaScript frameworks.

Gemfile – the Gemfile contains all of the gems that are included in the application; this is where you will place outside libraries that are utilized in the application. After any change to the Gemfile you will need to run: bundle. This will call in all of the code dependencies into the application. The Gem process can seem like a mystery to new developers, but it is important to realize that the Gems that are brought into an application are simply Ruby files that help extend the functionality of the app.

Gemfile.lock – this file should not be edited; it displays all of the dependencies that each of the Gems contain along with their associated versions. There have been times where I discovered application bugs due to varying Gem’s dependencies.

README.rdoc – the readme file is an important place to document the details of the application. If the application is an open-source project, this is where you can place instructions to other developers, such as how to get the app up and running locally.

Scaffolding the application

Scaffolding vs. model/controller generation vs. building from scratch

When developing Rails applications developers are given a wide range of options for building the app. This especially holds true for the automated code creation process that Rails calls generators. To create a new element in the application you have three main options:

  • Using a scaffold to generate the entire module. This process involves the app assuming that you want the feature to have full CRUD functionality. CRUD stands for: CReate, Update, and Delete, which are the core building blocks of many database-driven applications. As helpful as the scaffold process is, more experienced developers will many times opt out of using them since they create quite a bit of unnecessary code that can be confusing later on. As a developer it is considered a best practice to not let the application have code that is not utilized, since unused code can confuse future developers looking at the project and lead to issues.
  • Using generators for the model and controllers. These generators can be extremely helpful by allowing developers to efficiently perform tasks such as: creating database tables along with their associated model files, building custom controllers and corresponding view files, along with being connected with other automated tasks such specific Gem rake tasks.
  • Building from scratch. If you are new to Rails development it may seem like many of the generators and automated tasks are ‘magic’ and perform tasks that mere human developers could not do; however, that is not the case. Everything that a generator does a human can do as well. It is not considered common practice to select this option since it is slower and can be more error-prone. However, when learning Rails it can be helpful to do this sometimes to get a better understanding of how the generators work in the backend.

For simplicity’s sake I will start out with using a scaffold. Run the following command in the terminal, and make sure you are at the root of the application directory when you run this:

Creating the first scaffold

rails g scaffold Project title:string description:text percent_complete:decimal

What do scaffolds create?

If you look at the console output, you can see exactly what the scaffold creates. Below is a breakdown on each element:

Creates the database migration file for creating the new database table
invoke active_record
create db/migrate/20150718044101_create_projects.rb

Creates a model file – this is where you will configure behavior such as: database relationships, custom algorithms, custom scope, callbacks, validations, and many other items. The complex behavior for the table should be stored in this file.
create app/models/project.rb

Sets up the Minitest module with some sample tests for models (this will only be shown if you did not skip the tests during the application generation process)
invoke test_unit
create test/models/project_test.rb
create test/fixtures/projects.yml

Configures the full set of routes for the feature
invoke resource_route
route resources :projects

Creates the table’s controller and preloads it with methods that will let you create records in the database, edit those records, and delete, along with the ability to display all of the items in that table or a single record.
invoke scaffold_controller
create app/controllers/projects_controller.rb

Creates views and preloads them with template HTML – this includes a full web form that will automatically let records be added and edited.
invoke erb
create app/views/projects
create app/views/projects/index.html.erb
create app/views/projects/edit.html.erb
create app/views/projects/show.html.erb
create app/views/projects/new.html.erb
create app/views/projects/_form.html.erb

Creates the controller tests
invoke test_unit
create test/controllers/projects_controller_test.rb

Sets up a blank view helper file where you can add custom methods that can be called from the view file. For example, when I have an array of options that I want to call from several forms in the application, I will create a helper method and simply call that method from the forms so that I am not duplicating code.
invoke helper
create app/helpers/projects_helper.rb
invoke test_unit

Creates the ability to output the index and show values via JSON. If an app needs to supply an API with its data, this is a very helpful shortcut.
invoke jbuilder
create app/views/projects/index.json.jbuilder
create app/views/projects/show.json.jbuilder

Creates a dedicated Coffeescript file and SCSS file for styles
invoke assets
invoke coffee
create app/assets/javascripts/projects.coffee
invoke scss
create app/assets/stylesheets/projects.scss

Creates a new SCSS file for the entire application. I always delete this file since I have never found the built-in styles from the scaffolds very helpful.
invoke scss
create app/assets/stylesheets/scaffolds.scss

Updating the database

If you try running the application now, it will throw an error that says: ActiveRecord::PendingMigrationError because it recognizes that there are database migrations that have not been run yet. The database is not officially updated when you run the scaffold (or any of the generators); it simply creates the migration file. If you go to db/migrate you will see a new file. My file has the file name:

db/migrate/20150718044101_create_projects.rb

The long number in front of _create_projects.rb is the timestamp. This helps provide a namespace for the migration so that it will not have a conflict with a migration in the future. If you open this file you can see all of the proposed database changes that the scaffold creates:

 

    
    class CreateProjects < ActiveRecord::Migration
      def change
        create_table :projects do |t|
          t.string :title
          t.text :description
          t.decimal :percent_complete

          t.timestamps null: false
        end
      end
    end

 

 

To analyze what this is doing, it is best to start from the very top:

This is a Ruby class. The scaffold named it for us and called it: CreateProjects and it inherits from ActiveRecord::Migration, which is a Rails class that contains a large number of methods to assist developers with managing the database. Since the migration inherits from ActiveRecord::Migration, we can move to the next lines and the methods: change and create_table. If you are new to object-oriented programming, this essentially means that because our class inherits from ActiveRecord::Migration we inherit the publicly available methods associated with that class. So we can use the create table method to create a new table in the database and add columns and associated data types.

class CreateProjects < ActiveRecord::Migration

Finishing up our analysis of the migration, you can see the attributes we gave the scaffold are all here and the code below means that the migration will create columns for: title, description, percent_complete, and then timestamps.

    t.string :title
    t.text :description
    t.decimal :percent_complete
    t.timestamps null: false

You may notice that we did not add ‘timestamps’; these are built in by Rails automatically and will give our database table columns that save when a record was originally created and a timestamp for every time the record is updated. You can technically remove these if you do not want them, but that is strongly discouraged since there is a low cost associated with having these columns in the database and you will most likely find them very useful later on. Knowing the date and time when a record is created or edited can be helpful for tasks such as sorting by the newest element in a database, or finding the last record that was edited.

Now to finalize the scaffold and update the database, run:

rake db:migrate

After running this you can now take a look at db/schema.rb and see that our new table is added to the schema file. If you restart the Rails server, the error message will be gone and the app will load like before.

If you go to localhost:3000/projects you can see the functionality that was created by the scaffold, including the ability to create records, edit them, view them, delete them, and view all of them at the same time. Nice work – you have a working application already!

Rails console

The purpose of the Rails console

While the Rails console has a large number of features, I use it daily for accessing the database and running test queries. Technically you could do all of this in the code and browser, but it is much more efficient when performed in the console. For example, if you wanted to run a query to see the results in the browser, you would need to update the controller, possibly update the corresponding view to ensure all of the columns are captured, and then go to the browser and refresh it to run the query; whereas if you wanted to test in the console you would simply run the command and immediately view all of the values returned from the query. This is also a great way to debug your application since it makes it possible to integrate debugging text and even breakpoints into the code and view the issues in depth in the console.

How to run queries in the console

To start up the rails console, first make sure that you are in the root of the application, and then run:

rails c

This will load the Rails environment and give you command access to the database, along with the ability to run full methods and pretty much everything you would want to do in the application.

To exit the console, run the command:

control d

Running in sandbox mode

Since running code in the Rails console can make changes to the database and cause side effects that you may not want, running in sandbox mode can be very helpful. Whenever I have an algorithm that I’m testing out and I am unsure of how the application will behave, I run in sandbox mode to ensure that any changes made by the script will automatically be undone after leaving the console. The way that Rails accomplishes this is by rolling back all changes during the Rails console session. Please note that even though this works great for rolling back database changes, if your scripts contact outside APIs, those changes will not be rolled back, so always be careful when testing scripts that contact outside services.

To run the console in sandbox mode, run the following command:

rails c --sandbox

Creating records in the database from the console

To create records in the database you can run creation scripts the same way that you would run in the code. I want to create some test Projects to work with, so I’m going to run the following script:

 

		
    rails c

    10.times do |project|
      Project.create!(title: "Project #{project}", description: "My cool description")
    end

 

If you are familiar with Ruby syntax, this will look familiar to you, but if not, I will walk through what this creation script is doing. The first line is the start of a code block. It will iterate 10 times and will give us access to an iterator variable ‘project’ that can be utilized as a unique value in the code block.

The Project.create!(title: “Project #{project}”, description: “My cool description”) script creates a new record in the Project database table and assigns the values for the title and description. The ‘create!’ method has the ‘!’ symbol, which is optional. I like using it since it will give an explicit error message if the creation process fails. If I were to run Project.create(…), if it would fail it would only return false, but not return an error, and in development mode I want the error messages to be as descriptive as possible. Inside of the parentheses Rails utilizes the hash syntax, with named attributes, so you simply supply the column name, followed by a colon, followed by the value you want to assign to it.

Lastly, the “Project #{project}” syntax is the way that Ruby uses string interpolation. By leveraging the ‘project’ iterator variable, we’re able to give a unique title value to each record that we created.

– Querying records in the database from the console

Now that we have some data in the database, we can run queries. Since we only have one table created, the queries will be relatively simple, but it is important to become familiar with how the query system works since you will be utilizing it daily as you build out applications.

Below are some queries we can run:

Project.all

> Returns all of the records for the Project table

Project.count

> Returns a count of how many items are in the project table

Project.find(1)

> Returns the record with the ID of 1

Project.find([1, 5, 7])

> Returns an array of records where the ID is: 1, 5, and 7

Project.last

> Returns the last record in the table

Project.first

> Returns the first record in the table

Project.where(title: “Project 0”)

> Returns an active record relation of any/all records where the title is exactly: “Project 0”. This can be an issue for new Rails developers since it may first appear that it returns a single record, but it actually returns a collection. This is an important distinction because if you attempt to call a method on the returned value it will throw an error. This is different than if you call Project.last, which returns a single record. For example, if you run Project.where(title: “Project 0”).upcase it will throw an error, whereas Project.last.upcase will work.

Deleting records in the database from the console

Deleting records in the database it is relatively simple. You first need to find the record or records that you want to delete and then call the delete method on it. A sample delete query would be:

Project.last.delete

If you wanted to delete all of the records in the table, you can run the command:

Project.delete_all

Updating records in the database from the console

In order to edit/update values in the database simply call the 'update' method, as shown below:

Project.last.update!(title: "My New Title")

The "!" (commonly referred to as ‘bang’) following the 'update' method has the same behavior as when called with the create method, where it will return a descriptive error message. You may also notice that you do not need to call all of the values in the record – only the values that you want to change. The other columns will remain unchanged.

Rails Routing

What are RESTful routes

If you have never used or heard of RESTful routes, the concept may be intimidating, but it is helpful to understand that the concept of REST is simply a convention that assists developers in following best practices and using standard naming practices.

REST stands for REpresentational State Transfer, and leverages common names for HTTP protocols such as PUT and GET requests. If this still does not make sense, below is a simple way to understand what each protocol does:

GET – Returns values from the database
POST – Creates a new record in the database
PATCH/PUT – Updates a record in the database
DELETE – Deletes an item in the database

Basic fundamentals of routing

The topic of routing in Rails could take up an entire book since the routing system is very complex and allows for quite a bit of flexibility. However, below are some of the most common routes that I utilize:

This route will create a route for: url.com/about and map it to a controller called Pages and method ‘about’, and display the view ‘views/pages/about.html.erb’
get ‘about’, to: “pages#about”

This route will create paths to the edit, update, and show views for the Products controller, but not for delete:
resources :products, only: [:edit, :update, :show]

This is how you redirect to another site
get ‘contact’, :to => redirect(“http://www.someothersite.com”)

This is how you declare what the homepage should be. This will find the Home controller and display the index method and view:
root ‘home#index’

Here is how to set a ‘catch all’ route; this ensures that if a user tries to go to any page that does not exist, they will be redirected to the homepage:
get ‘*path’ => redirect(‘/’)

This only touches the basic concepts of routing in rails. There are also items such as nesting, member block, etc., that are all very helpful. For a full description of how to utilize routing, please refer to the comprehensive guide: 

Configuring routes

When we ran the Project scaffold it added a line inside of the config/routes.rb file with the code:

resources :projects

This is some Rails syntactic sugar for grouping all of the CRUD routes into a single line. Since RESTful routes include a specific naming convention, this includes the routes for: indexing, showing a single value, creating a new record, editing a record, and deleting a record.

To remove the default Rails landing page, I will set the homepage to our Project’s index page with the following code:

root "projects#index"

Go to ‘localhost:3000’ in the browser and you will see that the homepage is now the Project index page.

Updating the views

What are erb view files?

Since HTML files are not able to render Ruby code directly, it is necessary to utilize a file type that can process Ruby properly, which is where erb files come in. ERB stands for ‘Embedded Ruby’, and as the name implies, they give the ability to embed Ruby code and have it processed in the view. If you look at the Project files that were created with the scaffold you can see ‘app/views/projects’ has several view files that all have the file type of: ‘html.erb’.

Syntax for erb files

There are two main ways to integrate Ruby into erb view files, and it is important to know the distinction. The first has the syntax:

<% some ruby code %>

The second is:

<%= some ruby code %>

The '<%' means that the Ruby code will be processed, but it will not display to the user. This syntax is typically used for integrating iterators, where you would not want the query displayed. You can see an example of this in the ‘views/projects/index.html.erb’ file around line 16:

<% @projects.each do |project| %>

This will iterate through the value passed through the Project’s controller’s index action (more on that later), and make the value of each record available through the ‘project’ iterator variable.

If you move down to lines 18-20, you can see the second syntax:

<%= project.title %><%= project.description %><%= project.percent_complete %>

 


This will render the value for each of the Project attributes: title, description, and percent_complete. The ‘project’ iterator variable tells the view that for that iteration it should render that specific database record, and because it utilizes the ‘<%=’ syntax it will display it in the browser. If you changed it to ‘<%’, the query would still run, but it would not render in the browser for users to see.

Different options for views, namely Haml

Erb is the embedded Ruby option that ships with Rails by default, but there is another option that can be easily installed, called: Haml. Haml allows for a cleaner code interface and enables the view pages to look more like pure Ruby code instead of HTML code. For more information on how to utilize Haml, feel free to reference their documentation: http://haml.info/

Working with the Rails asset pipeline

The Rails asset pipeline allows for a direct connection between the application and assets such as: images, stylesheets, and JavaScript files. In addition to allowing developers to access the assets to integrate them into the application, it also is structured so it can compile the assets to assist with application performance.

Asset pipeline images

In order to store images and access them from within the application, place the image files inside the ‘app/assets/images’ directory. You can then access them from within the application by calling them from an erb file. For example, if I want to place a logo in the header of the application I would add a logo file in the ‘images’ directory and then call it from the master layout file. The code is below:

<%= image_tag('logo.png') %>

Notice that the 'image_tag' method automatically knew to look in the correct folder. The 'image_tag' has some additional options, such as dictating the size of the image, so I could also use code like this if I wanted to force the size of the image to be a specific width:

<%= image_tag('logo.png', width: '100px') %>

There are a long list of options for ‘image_tag’ that you can use to work with images. Please reference the API documentation here for the comprehensive list:

Asset pipeline CSS

If you are familiar with CSS, you are aware that you can integrate CSS styles using three methods: inline, embedded, and in an external stylesheet. With the Rails asset pipeline, your CSS files are stored in ‘app/assets/stylesheets’. You may also notice that a ‘projects.scss’ file was automatically generated by the scaffold. Any SCSS/CSS styles you place in this file will be available to the application. The app looks at the master ‘stylesheets/application.css’ file to see which stylesheets to load, and the ‘*= require_tree .’ line of code tells Rails to load all styles within the stylesheets directory.

You can test this out by adding the style to the ‘projects.scss’ file:

      html {
        background-color: black;
      }

Refresh your browser and you will see that the background for the site is now black.

Asset pipeline JavaScript

In addition to stylesheets and images, the asset pipeline also supplies a spot to place the custom JavaScript files. You can find these files in ‘app/assets/javascripts’. Following the pattern found with the stylesheets, the JavaScript structure has a master application.js file that brings in all of the JavaScript files in that directory (unless you tell it not to).

You can test this out by adding the following line of Coffeescript to ‘javascripts/projects.coffee’:

alert "Hey there!"

Refresh the browser and you will receive a JavaScript pop-up box saying, “Hey there!” (I’d remove it after testing it since it will load on every page, which will be pretty annoying).

Updating the controllers

The purpose of controllers

Controllers in a Rails application can be thought of as the traffic conductors for the data. The controllers connect the models, views, and routes. To make the process more straightforward, think in terms of the following process:

  1. The view looks to the controller and only has access to the instance variables that the controller makes available. Those instance variables will contain any/all data coming in from the database.
  2. The routes file looks to the controller and ensures that the methods in the controller match the items in the routes file. If you followed the scaffold process you will see a ‘resources :projects’ route that encapsulates all of the: index, new, show, update, edit, destroy, etc., methods in the generated controller.

The controllers can also help to protect against security issues, in Rails 4+ the controller forces all attributes submitted through forms to be declared as a strong parameter. You can see this in the ‘app/controllers/projects_controller.rb’ file at the bottom, where it has the method ‘project_params’. Anytime you perform a database migration, you need to update this method to include the new columns.

Antipatterns for controllers

One of the top issues that I will see with legacy Rails applications that I consult on is the misuse of the controllers. Because it can be easier, many developers will place the logic of their application into the controller, including custom algorithms and complex query scopes. However, this can be troublesome because it means that the scopes and methods that you declare in the controller can only be used in that view – whereas if you placed the logic for each of your tables in the model files, they could be called from other controllers. A good example of this would be our Project model; if you want to create a dashboard that displays statistics for the projects on multiple pages that have a custom query scope, you would need to duplicate code in different controllers, instead of being able to call the same scope/methods. This may not seem like a major issue for small applications, but for mission critical applications, it can be critical to ensure that behavior can be altered in one location, instead of worrying about changing identical code throughout the application.

Customizing queries in the controller

As a default query, the scaffold will generate code such as:

Project.all

This will call all of the items from the Project database, which is fine in the beginning. However, if we want to make our Tasker application scalable, this would be a horrible idea. If we end up with thousands or millions of tasks, the page load times would be astronomical. This is why it becomes necessary to customize queries. A simple customization would be to limit the page to the last 50 queries, which can be accomplished by updating the index action to something like:


def index
Project.all.limit(50)
end

 

This is a very simple implementation. Eventually you will want to add features such as pagination or infinite scrolling. All of this can be implemented via Gems and is beyond the scope of this tutorial.

Other ways you can easily customize the scope would be to implement a 'where' query, such as:


def index
Project.where(description: "My cool description")
end

 

Typically you would not build a query based on the description, but it is a good example of how to limit the values returned from the database based on query criteria. In most cases I would run a query that would limit what is shown via the index action to a specific user. This cannot be performed with our current database structure since we have not added a user yet, but if we pretend that there is a User model, you could run a query such as:

Project.where(user_id: current_user.id)

If we had a User model and a current_user method (which we will have soon), this will return all of the projects that belong to a specific user.

Working with the model files

The purpose of model files

One of my favorite tasks in a Rails application is working with the model files. This is where you can be very expressive with the custom algorithms that you want to utilize and you also have direct access to the specific database record. When building out an application, I will spend a large portion of my time in the model file.

The type of code that should go in model files

At the end of the day the model file is a Ruby class. It will typically inherit from the ActiveRecord::Base class, which means that it has access to a number of methods that assist in working with the database. However, you can treat it like a regular Ruby class, allowing you to create methods, data attributes, and everything else that you would want to do in a class file.

If you were to look at a typical model file in one of my production applications you would find: custom scopes, default settings for database columns, validations, model-to-model relationships, and callbacks. If any or all of those items sound unfamiliar to you, do not worry, as I will cover all of them and you will learn how to integrate them into a Rails application.

Creating model files that aren’t active record models

There are times when you want to create a Ruby class that does not inherit from ActiveRecord::Base. You would do this when you want to create a helper class that you want to be able to call from multiple files. To create a model file simply create a new file in the model directory and name it with the same naming structure as the class name. For a contrived example, let us create one for our application. Create a new file in the model directory called:

counter.rb

Inside of the models/counter.rb file, add the following code:

    
    class Counter
      def self.calculate_percent_complete(completed_tasks, total_tasks)
        completed_tasks.to_f / total_tasks.to_f * 100
      end
    end

 

This is not a class I would create for a real-world application since it would make more sense to have this logic reside in whatever class will handle the process for updating the ‘percent_complete’ attribute. However, this is an easy-to-understand method that illustrates how you can create class files in the model directory to handle application behavior and can be called from anywhere in the app.

To test it out, open or restart the Rails console (if you still have the console open, enter: reload! which will reload the console session and give it access to any changes in the application). Run the following command to test out our new file:

Counter.calculate_percent_complete(8, 10)

Which will correctly return: 80.0

To analyze what this is doing, let us go line by line through the code. The 'class Counter' declaration says that we are going to create a new class that has no parent class, so it will not inherit from any Rails classes.

The def ‘self.calculate_percent_complete(completed_tasks, total_tasks)’ method declaration states that it is a class method (class methods are created by using the ‘self’ syntax). By making this a class method we are able to call it directly on a single line; if it did not have the ‘self’ declaration, we would need to create a new instance of the class, store it in a variable, and then call the method on that new instance. I typically prefer to use class methods when I am going to use helper methods like this. The ‘(completed_tasks, total_tasks)’ are simply method arguments. They could be called anything, but it is a good idea to give them names that explicitly describe what they need to be.

Lastly, we perform a simple percent calculation to find out what the percentage of the tasks are completed, making sure to convert the values to the float data type with the method call ‘.to_f’ to ensure that the percent will be accurate.

Adding custom scopes to models

Since loading up controllers with too much code is considered a very bad practice in Rails applications, you will discover that creating custom scopes in the model files is a common practice. Essentially what this means is that you can dictate specific queries in the model file and those queries essentially operate like functions in the rest of the application.

For our app, we can add a custom scope below in the models/project.rb file:

 scope :almost_completed, -> { where('percent_complete > 75.0') }

And then update the controllers/projects_controller.rb file:

    def index
      @projects = Project.almost_completed
    end

 

If you look in the browser, when you switched the code in the controller’s index action from the default ‘@projects = Project.all’ to our new custom scope, you can see that it no longer shows the test projects that we created (unless you increased some of their ‘percent_complete’ values to above 75.0). To ensure that this is working, let’s test it out and update one of the projects.

Start a new Rails console session and run the following command:

Project.last.update!(percent_complete: 80.0)

Now start the Rails server again and refresh the projects’ page and you should now see the project that we updated. This means our new scope is working. This obviously would not be a good scope for the index page, but if you wanted to have a page dedicated to projects that were close to being completed, or a background task that sent out emails when tasks were getting close to the finishing line, you could call this scope instead of having to duplicate the query each time.

This is a good practice for a number of reasons:

  • Scopes are descriptive – they can succinctly explain what the query is going to return, and are therefore good for code readability.
  • Scopes only have to be managed in one spot. This means that if you want to change the query you do not have to make the alteration throughout the codebase; you can make the change in one location and it will automatically propagate throughout the app.
  • Scopes can be called like functions. This capability makes it straightforward to call them throughout the application.

Adding data defaults to a model file

With Rails application you have the ability to set default data a number of ways. Two of the most popular options are:

  • Setting the defaults in the database itself. I personally do not like this option since it requires more work to alter the default (or remove it) later on.
  • Setting the defaults in the model file. This is my favorite way to set defaults. It is flexible and allows defaults to be managed with minimal work. It also can be treated like regular code (something I am always a fan of). For example, if you wanted to set a default value based on dynamic logic, such as a conditional, this approach allows for that.

So let us integrate a default value for the project’s percent_complete column when a new project is created:

after_initialize :set_defaults

def set_defaults
self.percent_complete ||= 0.0
end

As usual, let us analyze what is going on here line by line. The ‘after_initialize :set_defaults’ is a callback that will be run immediately when a new Project is being created. If you test this out in the browser you will notice that when you go to create a new Project via the form page, the ‘0.0’ value is already set. That is because I used the after_initialize instead of after_create callback. Essentially the way this works is that when a new project is being created, it will run the methods listed after the after_initialize method. In this case, it will run the set_defaults method.

The code inside of set_defaults may look a little different if you are new to Ruby. We first call on the instance of the newly initialized project with ‘self’, and then we call the attribute that we want to set ‘percent_complete’. Next, we call Ruby’s conditional assignment operator ‘||=’. This will first look at the value attributed to ‘percent_complete’ and if it is nil/false, it will assign the value to the right of the operator. The reason why we need to use the conditional assignment operator is because if we simply used equal, the default would be set every time the form loads, which is obviously not what we want, especially when we are in editing/updating mode.

With this approach the model completely controls the default value and we can easily alter the default value with small code changes.

Integrating validations

If you go to the application right now and try to create a new project without a title and description, you will find that it lets you do it, which is most likely not the behavior that we want considering projects without titles would not make for a great user experience.

To integrate a validation it is a pretty simple fix. Add the following line of code to models/project.rb:

validates_presence_of :title

If you go back to the application and try to create a project without a title, it will now give the user a warning and block the project from being created without a title. If you want other attributes to always be included, you can add them on the same line, like so:

>validates_presence_of :title, :description, :percent_complete

Integrating callbacks

Even though they can be overused, the callback feature is one of my favorite parts of Rails. Essentially this enables the application to spawn methods automatically at varying stages of table records being created. The full list of potential options are:

before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback
before_destroy
around_destroy
after_destroy
after_commit/after_rollback

You already know how to use callbacks; we are currently using one to set the defaults for the our Project model. However, let us take another look by connecting it with a new module. This time we will build out a model from scratch instead of relying on scaffolds. Part of the reason is because I want to create a Task model that will be nested under projects, and it makes more sense to create this type of relationship manually since it will require a little more of a detailed integration than a scaffold provides. First, run a new model generator:

rails g model Task title:string description:text project:references

When you run this model generator you may notice that there are fewer files created with this generator. This is what you should see in the console:

 

    invoke  active_record
      create    db/migrate/20150723032551_create_tasks.rb
      create    app/models/task.rb
      invoke    test_unit
      create      test/models/task_test.rb
      create      test/fixtures/tasks.yml

 

If the project:references call in the generator looks unfamiliar, it is a nice shortcut that Rails provides that sets up a foreign key between the task and project models. To update the database make sure to run:

rake db:migrate

If you look in the schema file you will now see the new Task table is live with the parameters that we supplied. You will also notice that there is a ‘project_id’ attribute that was automatically added. This is the reference that was automatically created that connects the task to a project. If you open up the models/task.rb file you will see the references call automatically added a belongs_to relationship method call:

>belongs_to :project

This sets up the initial model connection, but you still need to add the second half of the connection. In this case our project.rb file needs to be informed of the connection. Because each task is going to ‘belong_to’ a project, each project is going to have the ability to have many tasks. In Rails this is denoted by a ‘has_many’ call. To implement this, update the models/project.rb file by adding this line:

has_many :tasks

You can test this in the console by running:

Project.last.tasks

If you have everything set up properly, this will return ActiveRecord associations property. If it is not set up properly, it will return an error.

Now that our app has projects and tasks underneath it, we can build the callback by adding the following code to the task.rb file:

    class Task < ActiveRecord::Base
      belongs_to :project

      after_update :update_percent_complete if :mark_completed?
      after_create :update_percent_complete

      scope :completed, -> { where(completed: true) }

      def mark_completed?
        self.completed == true
      end

      def update_percent_complete
        project = Project.find(self.project_id)
        count_of_completed_tasks = project.tasks.completed.count
        count_of_total_tasks = project.tasks.count
        project.update!(percent_complete: Counter.calculate_percent_complete(count_of_completed_tasks, count_of_total_tasks))
      end
    end

You may have noticed that we are also using our Counter helper method to help update the ‘percent_complete’ value for the project after a task is updated or created. This is quite a bit of new code, so let us go line by line to review exactly what is being done with this.

With the after_update and after_create callbacks we actually call the same method. There are a few ways of doing this, but for the sake of being able to illustrate how callbacks operate, I wanted to show that you can have processes (in this case the same process) start after a new object is created or edited. In the case of an updated process the update_percent_complete method should only trigger if the ‘completed’ attribute is set to true. We ensure that this is the case by adding the conditional of ‘if :mark_completed?’ after the after_update callback. This will first look at the ‘mark_completed?’ method to ensure that it returns true prior to moving onto the update_percent_complete method.

This is by no means the cleanest code that I have ever written, and I would not do it exactly like this in production since there is some duplicate code. However, this should give you a clear idea of how it is possible to have workflows generated based on: created record, updated records, and even conditionals.

As convenient and powerful as callbacks can be, it is the mistake of many developers (including myself at times) to throw a large number of processes in as callbacks; this can cause issues later on down the line and has earned the term ‘callback hell’. A great example is when complex, time-consuming processes are declared as callbacks for a model. I have run into times where bugs would creep up in applications, where the callback was too time/memory-intensive and would cause errors; and without having a clear view into the issue, I have spent countless hours on attempts to fix the core action when it was actually the callback causing the problem. This is why it is considered a poor practice to ‘stick’ too much logic into callbacks directly. If you have a complex process that needs to start based on a callback, it is considered a much better practice to generate a background task that will take care of the workflow.

Database changes

What is a database migration?

When I was a young PHP developer it was a common practice to make direct changes to the MySQL database, using tools such as PHPMyAdmin. This was fast and convenient, but it was incredibly error-prone. Modern development practices have taught us that versioning database migrations will help to protect data and overall application integrity.

So what is a database migration? If you have never worked with databases before I will assume that you have used Excel spreadsheets before. An Excel spreadsheet has columns that list each of the attributes in the database and rows that represent each of the records in that spreadsheet. In a database you can visualize attributes as spreadsheet columns. These columns have rules, such as the type of data allowed in those records. For example, if you have a ‘date’ column you would want to have a ‘datetime’ date type to ensure that all of the data in that column is the same format.

If you want to make changes to the database, you do not want to simply add a new column since that change could have adverse effects on the application. Instead you would want to create a database migration that updates the overall database schema, which essentially creates a snapshot of the database structure. This way, if you make a mistake, it makes it straightforward to revert back to the previous database version without having to redo the entire database system.

The Rails applications workflow is to create a database migration file, which we have done several times, and then run the official migration. This process lets you analyze the potential changes to the database prior to committing the change to the schema file. This is the reason why, when we ran the scaffold and model generators, we had to run separate commands to run the migration itself. The generator only creates the migration configuration file; the migrate command is still required to make it all official.

This is a good idea because there are many times when I will utilize a generator and it is not until I have analyzed the migration file that I realize that I forgot an attribute or I misspelled a data type, etc. This two-step process lets you as a developer ensure that all of the potential changes to the database are accurate.

Different ways to change the database schema

Database schema files can be changed through migrations or schema loads. For day-to-day work you will want to utilize migrations, but if you are taking over a legacy application or possibly deploying to production for the first time, you may want to take advantage of the schema load command. It is considered a very bad practice to ever make changes to the db/schema.rb file directly, since that workflow could be very error-prone. However, due to Rails flexibility, it is technically possible to make changes to that file and then run the command:

rake db:schema:load

However, this should be used very rarely since it is a Rails antipattern for daily development and could cause a large number of issues. Instead, you should create migrations and then migrate the full database manually. For example, if we wanted to add a new attribute to the ‘projects’ table, you could run the command:

rails g migration add_stage_to_projects stage:integer

This will create a migration file and add a new column called ‘stage’ to the project database table. However, if you check the schema file you will notice that the change is not live yet. To actually update the database you will need to run the migration with the command:

rake db:migrate

Now check your schema file, and you will see the new ‘stage’ column added to the table. If you want to keep the column and simply change the data type, run a change_column migration. Let us change our new ‘stage’ data type from an integer to a string:

rails g migration change_data_type_for_stage

This will create a new migration file that we can get to by going to: db/migrate and finding the file at the very bottom of the list (which is the newest file created). My file is titled: 20150725044512_change_data_type_for_stage.rb but your file will be different since the long number sequence at the beginning of the file name is automatically generated based on the time of the migration. Upon, opening the file, you will find this migration is pretty empty except for the migration wrapper. Mine looks like this:

    
    class ChangeDataTypeForStage < ActiveRecord::Migration
      def change
      end
    end

In this case I wanted to show you how to manually add the migration details manually so you can see it really is not that scary to do it without the shortcuts.

I will add the following code to change the data type:

    
    class ChangeDataTypeForStage < ActiveRecord::Migration
      def change
        change_column :projects, :stage, :string
      end
    end

 


The 'change_column' call is simply a Ruby method that has some arguments that we supply:

:projects is the name of the table we want to update
:stage is the name of the column that will be updated
:string is the new data type

After running:

rake db:migrate

You will notice that the database schema file now reflects the change and our 'stage' column has the 'string' data type instead of the integer that we originally created it with.

If you are doing this with a production application that already has data in a column that you changed the data type in, you will need to go through and run a script that updates the values in each of the records. For example, if our application was as production app and we changed stage from an integer to a string, I would need to create a console script that iterated through each record and changed the value to a string. Otherwise, the app would throw an error since the data type of all of the values in the database needs to match the data type declared in the schema file.

Integrating foreign keys into migrations

If you went through the last section you actually already know how to use foreign keys. With the call made to the model generator “project:references” this automatically added the column “project_id” to the table, and after integrating the has_many/belongs_to calls in the respective model files the table relationship is set – it is that easy!

Back when I started developing over a decade ago, setting up database relationships was much more of a manual process and error-prone. Therefore, when I started learning how easy Rails makes it to manage foreign keys in a database, I was very excited and I could not imagine going back to the old way of setting up table relationships.

Adding columns to a database table

You have already seen how to change the data type for a column, but what happens when you want to add a column? It is a very similar process. Let us add a new column to the Project model to designate if the project belongs to a specific company division:

rails g migration add_division_to_projects division:string

By adding in the 'division:string' suffix to the terminal call, it will automatically add in all of the pertinent code into the migration file. If you look at the migration file it created, you will see the following code:

    
    class AddDivisionToProjects < ActiveRecord::Migration
      def change
        add_column :projects, :division, :string
      end
    end

 


This may seem like magic, but Rails takes advantage of metaprogramming and is always looking to make the process easier for developers. In the case of creating new columns, if you place ‘add_’ or ‘Add’ to the start of the migration description it will look at the end of the description and at the argument and put everything together for you. To break it down in detail:

‘rails g migration’ tells Rails that this is going to be a migration
‘add_division_to_projects’ is the migration description and tells Rails to ‘add’ a column to the ‘projects’ table
‘division:string’ is technically an argument (and you could supply multiple arguments if you want to create multiple new columns), and it says that you want to create a new column called ‘division’ with the data type of ‘string’

Make sure to run: rake db:migrate to ensure that the database is officially updated.

Removing columns from a database table

To remove a column from the database is pretty simple. To remove the new ‘division’ column from the projects’ table, run the following command:

rails g migration remove_division_from_projects division:string

This will create a migration file you can look at. This file contains a different method: remove_column with the table name, column name, and data type.

If you run: rake db:migrate now it will remove that column from the database.

Helpful Gems/Libraries

What are Ruby Gems?

One of the reasons why the Rails framework has grown by leaps and bounds since it started over a decade ago is due to the community of Ruby developers who have contributed to the framework itself, along with the libraries that aid in the rapid development of Rails applications. If you had to build every feature of your application from scratch, it would be a tedious process (almost like coding Java!). This is where Ruby Gems come into the picture. Gems are Ruby libraries that can be plugged into your application and give your application access to extensive functionality that could take a long time to create yourself.

Pretty much every programming language and application framework provides some type of code library ecosystem; the Ruby language has Gems. If you are new to Ruby, the concept of Gems may seem a little mysterious, but Gems are simply Ruby code modules that have been packaged in a way that they can be bolted onto the app.

In fact, Rails itself is actually a Gem! You can check this yourself by opening your Gemfile and looking towards the top of the file, where you will see something along the lines of:

gem 'rails', '4.2.0'

The 'Gem' tells Rails that the line will contain a Ruby Gem. This is actually a function that contains arguments. In this case the arguments are the Gem name and the version of the Gem.

When should I use a Gem?

It can be tempting to try and find Gems for every piece of functionality in an application, but you need to be careful because every Gem that you use creates a dependency on that Gem. With a small number of Gems it typically is not an issue, but if the list grows longer you may discover that varying Gems can cause conflicts with other Gems (or even your own application code).

I ran into a bug last year where I had an application that wouldn’t work no matter what I did to fix it. The error messages were vague and it took me quite a while to discover that a new Gem that I had added brought in a new pagination Gem that conflicted with the pagination Gem I had already integrated. I had to write a custom metaprogramming module to fix the issue, but it could have all been avoided if I had not relied so heavily on varying Gems.

And yes, you heard me right: Gems can include other Gems – this is where conflicts can occur. If you open up your Gemfile.lock file (never edit this file directly, as it is simply for reference purposes), you will see that it lists out not only all of the Gems utilized by your application, but it also displays all of the dependencies and nested dependencies for each Gem, and their associated version numbers.

So when should you use a Gem? The answer to this is going to be different for every Rails developer. Sometimes it is dictated by development experience and other times it depends on the requirements for the specific application. For my own part I have discovered that the longer I develop, the less I rely on a large number of Gems and instead I prefer to build out the core functionality by hand.

With that being said, I have a set of Gems that I use regularly and which have saved me countless hours of development and debugging work. Below are some of my favorites.

Carrierwave

Carrierwave is a Gem that enables developers to integrate file uploading into their applications. It is relatively easy to use and provides a core set of processes that make a very challenging task, file uploading, something that can be built in minutes. It also works well with other Gems, such as Fog and MiniMagick. Carrierwave is here.

Fog

Anytime that I use Carrierwave I also use Fog. Fog is a Gem that allows for a very straightforward interface with cloud services such as Amazon Web Services. Fog is here.

dotenv

This Gem provides a feature I include in literally every project that I build (I will also use the Figaro Gem as well). dotenv is a very simple library that enables developers to do something absolutely critical: securely store and access environment variables. Environment variables are items such as: API credentials, secret keys, third-party login credentials, etc. It is a very bad practice to place security-sensitive items such as secret keys directly in the code. Using Gems such as dotenv allow you to securely store those items in a single file (that is not committed to version control) and simply treat them like a global variable throughout the application. Then all you need to do on the production server is set up your configuration variable values and they will automatically work.

While this may not seem like a high priority, let me tell you a story about a time when I got lazy and did not remember to do this. I was in a rush and needed to build out a simple file upload module to an application. I had to get it live in a few hours, so instead of setting up and protecting my AWS (Amazon Web Services) environment variables, I simply placed them directly in the code. I made a mental note to move the credentials to the .env file (the file that dotenv looks in), but I forgot… It was an open-source project, which means that the code was publicly available to the Github community. Around 24 hours later I received an urgent call from Amazon. They said that in the past 24 hours my account, which had never gone over $20 a month, had ramped up dramatically and had generated a hosting bill of over $16,000!

Hackers are constantly monitoring Github for users pushing up credentials that can be stolen, so always protect your environment variables and learn from my laziness! dotenv is here.

Devise

Devise is one of the most popular Gems in the Rails community. It has over 400 code contributors to it at the time of this writing and nearly 3,000 code commits. If you have ever built a secure authentication system for a web application, you understand how time-consuming and error-prone it can be. Devise does the initial legwork for developers and enables tasks such as: logging in, registering, sending password retrieval emails, sending confirmation emails, and much more. It also does a great job of securing the user credentials for security purposes. Devise is here.

Pry

When it comes to working through code bugs, Pry can be an incredibly helpful tool for developers. The standard IRB terminal shell is very powerful, but it lacks certain features that are built into Pry, such as: source code browsing, syntax highlighting, shell integration, ability to run as a debugger, and much more. This may not be a Gem that you use in your first few projects since there is a learning curve to become familiar with it, but if you want to become an expert Rails developer, Pry may very well become a tool you use daily. Pry is here.

Smart Listing

This is a Gem that I have come to love lately when I need to build table-based projects. It combines a number of features that typically would take extensive coding, such as: AJAX-based pagination, AJAX-based searching, AJAX-based sorting, inline editing, AJAX deletions, AJAX updates, etc. The AJAX integration means that all of these tasks can be completed without users even having to have a page refresh, which provides a great user experience. Smart Listing is here.

Font Awesome

Font Awesome is a great library that includes a full set of icons that can be easily integrated into an application. Technically Font Awesome does not require a Gem to work since it is simply a font that could be included like any other font, but I prefer integrating the Gem into my apps since it makes it more straightforward to call the icons like code. Font Awesome is here.

Bootstrap

Bootstrap is a HTML/CSS/JS framework created by Twitter that enables developers to have a great set of style elements instead of starting from scratch with each project. Many developers take this too far and rely completely on the built-in Bootstrap styles, which gives their sites an inauthentic look. However, Bootstrap is very flexible and makes it possible to completely customize the styles so that your application can have a unique look and feel, while still benefiting from the prebuilt classes provided with the framework. This is an especially helpful tool if you need to create an application fast and you do not have time to spend on design. Even the built-in styles can be used so that your prototype will not embarrass you in a demo. The Gem is here.

Image / File uploads and management

In this module we will walk through how to integrate image uploads into the application, and all of the associated configuration options that are required to set up the functionality properly.

Integrate Gems to handle images

First, we need to bring in the Gems that will handle some of the core functionality. Add the following code to the Gemfile:

	
    gem 'carrierwave'
    gem 'mini_magick', '~> 3.5.0'
    gem 'fog'
    gem 'figaro'

After these have been added, run the following command in the terminal:

bundle install

This will bring in all of the Gems and their dependencies.

Securing config credentials

To securely store the environment variables, run the following command in the terminal:

figaro install

This should create a new file: config/application.yml – if it does not create the file (I have had this happen a few times), you can create it manually.

Inside of the config/application.yml file add the following code:

    
    AWS_ACCESS_KEY_ID: "your access key id"
    AWS_SECRET_ACCESS_KEY: "your secret access key"
    development:
      AWS_BUCKET: your_app_name-development
    production:
      AWS_BUCKET: your_app_name-production

Make sure to add the config/application.yml file path to your .gitignore file so that it does not get pushed up to your version control system. If you open up the .gitignore file you can simply add the line /config/application.yml file to the bottom of the file and save this. This will ensure that the credentials are not shared with the world.

Integrate with the AWS S3 API

In order to get the AWS access key and ID, log into the AWS admin console and get them from there. While in the AWS dashboard, go into the S3 page and create two new buckets. The region does not matter too much for non-mission-critical applications, and the name can be anything that you wish. I will typically give them the name of the app followed by ‘-development’ and ‘-production’ so that I can keep the uploads in different buckets based on the environment. Once you have all of the keys and bucket names, add them to the config/application.yml file and your app is ready to communicate with AWS – not too hard, right?

Managing uploads

Next you will need to create the configuration file. There is a generator for that. Run the following command in the terminal:

rails generate uploader TaskFile

Please note that TaskFile is an arbitrary name that could be named anything, but I do like the uploader to be descriptive. In this case the uploader will manage all of the images and files associated with tasks. This by itself will not let our Task model handle uploads. This is related to the application itself. After this portion is completed we will integrate the uploader with the database table.

This generator will create quite a bit of code. Let us clean it up a bit and replace it with the following code:

   
    class TaskFileUploader < CarrierWave::Uploader::Base

      # Include RMagick or MiniMagick support:
      # include CarrierWave::RMagick
      include CarrierWave::MiniMagick

      # Include the sprockets-rails helper for Rails 4+ asset pipeline compatibility:
      include Sprockets::Rails::Helper

      # Choose what kind of storage to use for this uploader:
      # storage :file
      storage :fog

      # Override the directory where uploaded files will be stored.
      # This is a sensible default for uploaders that are meant to be mounted:
      def store_dir
        "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
      end


      # Add a white list of extensions which are allowed to be uploaded.
      # For images you might use something like this:
      def extension_white_list
        %w(jpg jpeg gif png pdf mp4 wmv xls xlsx doc docx ppt pptx mov)
      end

    end

 


Following our pattern, let us go line by line to see what this file is now doing:

The TaskFileUploader class is inheriting from the Carrierwave class (CarrierWave::Uploader::Base to be specific), which means it has access to a number of Carrierwave methods that will be utilized in the file.

Many of the comments placed above the methods should be self-explanatory. For example, they clearly explain that we are bringing in the CarrierWave::MiniMagick and Sprockets::Rails::Helper modules, so that we have access to their functionality.

After this we call the ‘storage’ method and tell Carrierwave that we will be using Fog for our storage, and in this case we will be configuring Fog to utilize AWS for image management.

In the next method ‘store_dir’ we will declare where the files will be stored and what the naming structure will be. In this case we are going to create a file called ‘uploads’ and then create a folder for the model name, and then add some more unique characteristics with calls to mounted_as and model.id. This will essentially ensure that no two files will be named the same in their respective directories. This may not seem like a big issue, but it is smart if your application has hundreds/thousands/millions of files.

Finally, the extension_white_list is a descriptive method where we declare what types of file extension we will allow. Since it would be a bad idea to let users upload and/all types of files, this will ensure that only approved file types can be allowed. In this case we will allow quite a few, including: jpgs, gifs, png, pdf, mp4, wmv, Excel files, Word docs, PowerPoint documents, and Quicktime files.

This method takes advantage of some Ruby syntactic sugar with the %w{…} syntax. This is shorthand for declaring an array in Ruby – for example:

%w{a b c}

is equivalent to:

["a", "b", "c"]

Now that our uploader is configured we can add in a file uploader into the task form (which means we are going to have to create the ability for users to create tasks).

This will be a little bit of task if it is the first time that you have worked on it, so let’s take it one step at a time. First, let us create a controller to handle the data flow for our tasks:

rails g controller tasks show new edit

This generator will create a controller file, update the views and then make some changes to the route file (along with a laundry list of other items). You may wonder why we didn’t use a scaffold for tasks since if you analyze the controller you will see that we are going to have to do quite a bit of work that the scaffold. The truth is that this will be a good exercise in learning how controllers work (as opposed to letting the generators doing all of the work for us).

Since I typically like to tackle the most difficult parts of a feature first, let us look at the controller first. Open app/controllers/tasks_controller.rb and you will see:

    
    class TasksController < ApplicationController

      def show
      end

      def new
      end
      
      def edit
      end

    end

 


If you compare this with the controllers/projects_controller.rb file you will notice a pretty significant difference, and we will be borrowing quite a bit of the code for the tasks controller, but not all of it (which is part of the reason why we did not use a scaffold generator as well).

Let us start at the very top. Let’s first add:

    
    class TasksController < ApplicationController
      before_action :set_task, only: [:show, :edit, :update, :destroy]
      ...
    end

 


This before_action action method with the ‘only:’ declaration means that before the show, edit, update, and destroy methods, we want the ‘set_task’ method to run. We have not created any of these methods, which is fine, but this is a convenient method that will find whatever specific task is being referenced instead of each method having to do it separately. This follows the DRY (Don’t Repeat Yourself) principle that you will find throughout your Rails education.

Next, we will be adding the bulk of the code, updating and/or creating method for the rest of the functionality:

    
    def show
    end

    def new
      @task = Task.new
    end
    
    def edit
    end

    def create
      @task = Task.new(task_params)

      respond_to do |format|
        if @task.save
          format.html { redirect_to @task, notice: 'Task was successfully created.' }
          format.json { render :show, status: :created, location: @task }
        else
          format.html { render :new }
          format.json { render json: @task.errors, status: :unprocessable_entity }
        end
      end
    end

    def update
      respond_to do |format|
        if @task.update(task_params)
          format.html { redirect_to @task, notice: 'Task was successfully updated.' }
          format.json { render :show, status: :ok, location: @task }
        else
          format.html { render :edit }
          format.json { render json: @task.errors, status: :unprocessable_entity }
        end
      end
    end

    def destroy
      @task.destroy
      respond_to do |format|
        format.html { redirect_to project_url(@task.project_id), notice: 'Task was successfully deleted.' }
        format.json { head :no_content }
      end
    end

 


This functionality should be familiar and mirrors the methods and processes in the projects_controller.rb file. One item to note is that the show and edit methods do not require any code since all they need is access to that particular task instance, which our before_action gives them.

After this we will setup some private methods that will only be available to the tasks_controller (the tasks controller is not being greedy or anything like that; it simply does not make sense for any other files to have access to these methods):

    
    private
      def set_task
        @task = Task.find(params[:id])
      end

      def task_params
        params.require(:task).permit(:title, :description, :project_id, :completed)
      end

 


The set_task method is what our before_action calls. This simply finds the parameter for the URL and then finds specific task. After that we have our special task_params method. This method sets up our strong params (a security perquisite for Rails 4+ that makes us list out all of the potential items that need to be submitted via the form).

Now that you have your controller file setup, we need to clean up our routes file. Right now you should see something like this:

    ...
	
    get 'tasks/show'
	
    get 'tasks/new'
	
    get 'tasks/edit'
	
    ...

This is pretty ugly and can be replaced with:

    ...
	
    resources :tasks, except: [:index]
	
    ...

If you compare the projects_controller with the tasks_controller you may notice that the only method that is different is the ‘index’ method. This is because I do not really to care to show tasks outside of the projects that they reside in. And in fact we will refactor the entire project so that tasks reside only inside of projects, meaning that tasks will be nested in projects. We can do this in the controller by creating a new ‘app/controller/projects’ directory, and then moving the tasks_controller.rb file inside of that directory. In the config/routes.rb file make the following change to the routes:

    resources :projects do
	resources :tasks, except: [:index], controller: 'projects/tasks'
    end

Now if you open up terminal and run: rake routes, you will get:

Prefix Verb URI Pattern Controller#Action
project_tasks POST /projects/:project_id/tasks(.:format) tasks#create
new_project_task GET /projects/:project_id/tasks/new(.:format) tasks#new
edit_project_task GET /projects/:project_id/tasks/:id/edit(.:format) tasks#edit
project_task GET /projects/:project_id/tasks/:id(.:format) tasks#show
PATCH /projects/:project_id/tasks/:id(.:format) tasks#update
PUT /projects/:project_id/tasks/:id(.:format) tasks#update
DELETE /projects/:project_id/tasks/:id(.:format) tasks#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
root GET / projects#index

This will show you all of the possible routes for your app. You will notice that the tasks are now ‘nested’ inside of projects, which makes sense because a task should no longer ‘live’ outside of a project. Next, let us refactor our views around a little bit. Move the ‘tasks’ directory in the ‘views’ directory into the ‘projects’ directory. So you should now access your task view files via ‘app/views/projects/tasks/’

Inside of the ‘views/projects/tasks’ directory add a new partial. Partials in Rails are designated with an underscore, so create a file called:

'views/projects/tasks/_form.html.erb'

Inside of this file add in the following code:

 

  
    <%= form_for(@task) do |f| %>
      <% if @task.errors.any? %>

<%= pluralize(@task.errors.count, “error”) %> prohibited this project from being saved:

      <% @task.errors.full_messages.each do |message| %>

    • <%= message %>

<% end %>

      <% end %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.label :project_id %>
<%= f.text_field :project_id %>
<%= f.label :completed %>
<%= f.check_box :completed %>
<%= f.submit %>
    <% end %>

 

This is a pretty standard Rails form. We are creating form elements for a: title, description, project_id, and completed.

We still have some work to do to get this fully working. We need to make the following changes to our new, edit, and show files in the ‘views/projects/tasks/’ directory:

 

   
    new.html.erb:

Create a new task

    <%= render 'form' %>

    edit.html.erb:

Edit a task

    <%= render 'form' %>

 

If you try to run the app now, you will get all kinds of errors, mainly because the nesting process still requires a few changes. Open up the tasks_controller.rb file and make the following change to the class declaration:

class Projects::TasksController < ApplicationController

This tells rails that this tasks controller is nested inside of ‘Projects’. Now add a new before_action:

before_action :set_project, only: [:show, :new, :edit, :create, :update, :destroy]

This will let us access the parent project for every task inside each of the methods. This could eventually be cleaned up a little bit since we do not actually need to call this each time, but I will leave it for right now since it really is not hurting anything. Next, create the ‘set_project’ method and place it towards the bottom of the file in the list of ‘private’ methods:

    
    def set_project
      @project = Project.find(params[:project_id])
    end

We are almost done! Now update the ‘create’ method so it looks like this:

    
    def create
      @task = Task.new(task_params)
      @task.project_id = @project.id

      respond_to do |format|
        if @task.save
          format.html { redirect_to project_path(@task.project_id), notice: 'Task was successfully created.' }
          format.json { render :show, status: :created, location: @task }
        else
          format.html { render :new }
          format.json { render json: @task.errors, status: :unprocessable_entity }
        end
      end
    end

By adding the ‘@task.project_id = @project.id’ code the project_id for the parent project for the task will automatically be assigned. And then ‘format.html { redirect_to project_path(@task.project_id), notice: ‘Task was successfully created.’ }’ will redirect the user to the parent project, which seems like the most logical user experience.

Lastly, make the same redirect changes to the update and destroy methods that were made in the create method (format.html { redirect_to project_path(@task.project_id)…)

Restart the server and go to one of your project show pages, such as:

http://localhost:3000/projects/7

From there append the new route, such as:

http://localhost:3000/projects/7/tasks/new

And now you should see the task form. If you add a new task, the project’s percent_complete value should update each time you create a new task.

That was a ton of code! If you run into any errors, verify that each of the files and directories match the ones that I have pushed to the repository for this stage of the project. You can see them here:

Now that we have nested tasks, let us integrate our images.

Run a database migration:

rails g migration add_task_file_to_tasks task_file:text

Then run:

rake db:migrate

Before we can integrate the form element, we first need to add it to the list of strong parameters in the tasks_controller. Update the task_params method so it looks like below (noting the addition of ‘task_file’ at the end):

    
    def task_params
      params.require(:task).permit(:title, :description, :project_id, :completed, :task_file)
    end

Now add a new form element to ‘views/projects/tasks/_form.html.erb’:

<%= f.label :task_file %>
<%= f.file_field :task_file %>

Next, add our uploader to models/task.rb:

mount_uploader :task_file, TaskFileUploader

Finally, create a new file to manage the AWS API connection:

app/config/initializers/fog.rb

In that file place the following code:

    
    CarrierWave.configure do |config|
      config.fog_credentials = {
          :provider               => 'AWS',
          :aws_access_key_id      => ENV['AWS_ACCESS_KEY_ID'],
          :aws_secret_access_key  => ENV['AWS_SECRET_ACCESS_KEY']
      }
      config.fog_directory  = ENV['AWS_BUCKET']
      config.fog_public     = false
    end

Now go create another task, this time with a file, and see if it creates the task without any errors. If any errors pop up, go back and ensure that your code matches what we walked through exactly (and that your AWS API keys are correct in the application.yml file).

To verify that this code is working (prior to showing the file link like we will do shortly), you can open up the Rails console in the terminal and run:

Task.last.task_file

If everything is working properly, you should see some output that includes details about the file you uploaded.

How to show the tasks under each project with their respective files

Now that the tasks are being created under projects, it is actually pretty straightforward to display them to users. Update the views/projects/show.html.erb file to the following:

<%= notice %>

Title: <%= @project.title %>

Description: <%= @project.description %>

Percent complete: <%= @project.percent_complete %>

    <% @project.tasks.each do |task| %>
      Title: <%= task.title %> Description: <%= task.description %> Completed:  <%= task.completed %> <%= link_to "File", task.task_file.to_s unless task.task_file.blank? %>

    <% end %>

    <%= link_to 'Edit', edit_project_path(@project) %> |
    <%= link_to 'Back', projects_path %> |
    <%= link_to 'New Task', new_project_task_path(@project) %>

Most of the code is the same that came with the scaffold, but I have added:

    
    <% @project.tasks.each do |task| %>
      Title: <%= task.title %> Description: <%= task.description %> Completed:  <%= task.completed %> <%= link_to "File", task.task_file.to_s unless task.task_file.blank? %>

    <% end %>

This is a code block that iterates over all of the tasks assigned to the specific project that is being shown. There is quite a bit of code to look at here, such as:

<% @project.tasks.each do |task| %>

This grabs all of the tasks for the project and iterates over them.

Then we call each of the database attributes that we want to display with some descriptive text in front of them. Since we do not want to show a link saying ‘File’ unless there is actually a file that was uploaded, I added the conditional ‘unless task.task_file.blank?’ which means that the link will not be shown if no file was uploaded for that specific task.

<%= link_to "File", task.task_file.to_s unless task.task_file.blank? %>

Also, the ‘to_s’ method called on the task file renders the URL, which is why we are able to pass it to the link_to method.

Lastly, I added a link to easily create new tasks and assign them to a project with the last line of code:

<%= link_to 'New Task', new_project_task_path(@project) %>

I got the route by running:

rake routes | grep tasks

This looked through the routes and searched for any of them that referenced tasks (rake routes will display all potential routes if you remember from the last time we called it). In those search results, I looked for the route that would let me call the new method, which was ‘new_project_task’, from there I added ‘_path’ and saw that it required a parameter, in this case the @project.

Restart your server and navigate to one of the project show pages, such as:

http://localhost:3000/projects/7

If you already created tasks for this project, they should all show up now. If you have not created any tasks, you can create them with the link and they should automatically be rendered after saving them.

For your reference, here is the code at this stage of the project: https://github.com/jordanhudgens/tasker/tree/8a98c3b2f838e504b6be7d840d0f40976cfb9569

Authentication

When it comes to integrating authentication into your application, you can either build it in from scratch or leverage pre-existing tools that have already done the hard work for you. In this tutorial we will utilize the Devise Gem to build in the ability to: register, login, logout, and manage user details.

Devise installation

To integrate Devise into the application, follow the steps below.

Add the Gem to your Gemfile:

gem 'devise'

Then run:

bundle install

Then run the generator:

rails generate devise:install

The generator gives step-by-step instructions on how to finish the integration process. The first is to configure the mailer settings since Devise gives the app the ability to perform tasks such as emailing forgotten passwords. Update the config/environments/development.rb file with the additional line of code:

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

The second task is to ensure that the app has a homepage. We already have that covered, so we can skip ahead to #3. This is asking us to add Flash alert messages. This is easily handled by adding their sample code to the views/layouts/application.html.erb file:

<%= notice %>

<%= alert %>

This tutorial is not meant to be a design course (if you have looked at the app, this is obvious!), so you can place the code anywhere. I placed it directly above the <%= yield %> code call. In a production application I would spend time on the alert placement and how it looks, but for this app it is not a high priority.

 

We can skip #4 and move onto #5, generating the views. Let us run this last Devise generator:

 

rails g devise:views

This will generate all of the views we will need, including: registration pages, login pages, forms, edit pages, etc.

Even though this has given us a ton of code, we still need to create a model that will be our user database. Run the following code in the terminal:

rails generate devise User

This will create a migration file that is pretty extensive, along with a model file. If you open up the migration file, you will see that it automatically gives us all of the basic database columns that we will need to create users. It also has a few attributes that are commented out, but can be easily added before the migration takes place. These are:

Confirmable: this will integrate the workflow where users need to confirm via email prior to being able to access the site.
Lockable: this will allow you to lock users out if they have a specific number of failed login attempts. This is a feature that sites with high level of security, such as banking systems, typically implement.

To finish this out, run:

 

rake db:migrate

To test it out, start up the Rails server and go to:

http://localhost:3000/users/sign_up

You should now be able to sign up and have the app redirect you to the homepage.

Customizing Devise

If you want to use custom attributes with Devise, such as a username instead of an email address, we will need to implement some custom behavior. First, let us create a migration to add the username column to the User table:

rails g migration add_username_to_users username:string

Now run:

 

rake db:migrate

Our User model now has a username attribute. However, due to Rails 4+’s strong parameter requirements, we will need to add the username to controller. But wait… Devise did not create a users_controller.rb file like you may think that it would. Instead, to add custom attributes we will need to add them to the application_controller.rb file. Add the following code:

    
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << [:username]
  end

Now we simply need to add the ‘username’ attribute to the registration form element. Update the file ‘views/devise/registrations/new.html.erb’ and ‘views/devise/registrations/edit.html.erb’ with the following form element:

<%= f.label :username %>
<%= f.text_field :username %>

To test this out you will need to open a browser in ‘incognito’ mode since we have not yet built in the logout functionality.

Login process

 

To log in to the app you can open an incognito window (assuming that you are already logged in) and go to the URL:

 

http://localhost:3000/users/sign_in

 

Then type in the email address and password that you already created. If you type in the wrong credentials, it will give you an error message.

Logout process

 

To log out we will need to implement a button that will ‘destroy’ the user session. Open the ‘view/layouts/application.html.erb’ file again and add the following code somewhere on the page:

<%= link_to "Sign out", destroy_user_session_path, method: :delete %>

If you refresh the page you should see a ‘Sign out’ link. If you click it the app will log you out. However, you will notice that even after being signed out it will still say ‘Sign out’, which is not a great user experience. We can fix this by implementing some conditional logic into the application layout file. Instead of simply showing the Sign out link, let us only show that to users already signed in and we can show signup and sign-in links if they are not logged in. Update the application.html.erb code to include the following:

    
  <% if current_user %>
    <%= link_to "Sign out", destroy_user_session_path, method: :delete %>
  <% else %>
    <%= link_to "Sign Up", new_user_registration_path %>
    <%= link_to "Sign In", new_user_session_path %>
  <% end %>

Now if you refresh the page, you will see different links if you are signed in vs. if you are not, which is what a real-world app would do.

To view the code at this stage, feel free to review it here: https://github.com/jordanhudgens/tasker/tree/c6225a2c3ad15ab49962a1103a500f5f9fa9d088

Editing user information

Devise gives us the ability to edit user information right out of the box. To edit your information, first make sure that you are logged in, and then go to:

http://localhost:3000/users/edit

This page will let you edit all of the user information, including the new username attribute.

Deploying to the web

Deployment options

With a Rails project, you have a myriad of different options. Some of the popular servers and deployment systems are:

AWS EC2
EngineYard
Heroku
AWS Beanstalks
Digital Ocean
Rails Machine
ShellyCloud
And many more…

Each of the services have their own respective pros and cons. I will typically use Heroku for prototyping/piloting web apps and then I will deploy to an AWS EC2 instance or create a Digital Ocean Droplet. With that being said, I have a few clients that have large web applications that have been live with hundreds of thousands of users and do quite well on Heroku.

When it comes to ease of use for the developer, it is pretty hard to beat Heroku. I will show you how – in less than a few minutes, we can deploy our Rails app to the Internet. This is compared with deployments to platforms such as AWS that can take days, which begs the question, ‘Why wouldn’t I always use Heroku!’ It is a fair question and it mainly comes down to factors such as: Heroku tends to be quite expensive for larger applications; Heroku is pretty picky when it comes to temporary files and other similar items; and systems built from scratch give more developer flexibility.

Deploying to Heroku

Since this is an introductory course, we will walk through the most straightforward deployment using the Heroku platform. To begin, we will need to have a brief tutorial on how to use Git and Github.

While in the root of your application, run the following command in the terminal:

git init

This will initialize an empty Git repository for your application. Git is a source version control system that will let you manage your code at all the different stages of development. If you have not created a Git repo for the app, this will be the app’s initial commit, so let us add all of the files. In the terminal run the command:

git add .

This will add all of the code to the repo. If you run:

git status

You will see that all of the files have been added and are ready to be committed. The ‘commit’ process is where you can describe some of the details about this version of the app. In this case I am going to give a simple description, naming it the ‘initial commit’. You can commit your code with the following command:

git ci -m 'initial commit'

Now if you run:

git status

It will show that all of the code has been committed and we are ready to push to a remote repository. Open up a web browser and go to Github.com. If you have never used Github before, it is a centralized tool for storing your repositories. It also is a great resource for finding open-source projects. You may have noticed that all of the Ruby Gems that we have discussed are stored on Github. Register with Github (or sign in if you already have an account) and then click the ‘+’ icon on the top right-hand part of the site to create a new repository.

Give your repository a name. I gave this repo the name ‘tasker’. Make it public (if you want it to be free) and say that you do not want it initialized with a repository. After you create the repository, it will take you to a confirmation page that has the commands for adding your project’s code to the remote repository. It will have four options:

– Quick setup — if you’ve done this kind of thing before
– … or create a new repository on the command line
– … or push an existing repository from the command line
– … or import code from another repository

Since you already created the local code repo, you want to select the third option, ‘push an existing repository from the command line’. Click on the ‘copy to clipboard’ button on the right hand side and it will copy the commands to your clipboard. Now go to the terminal and paste it in. The first command will run automatically. Press return/enter to run the second command. If no errors pop up, you can go back to the Github repository and hit refresh and you should now see all of your code.

Now to get our app live on Heroku – If you do not have the Heroku CLI toolbelt installed on your system, then you will need to do that first. This link will have the most up-to-date instructions for downloading and testing out the toolkit: https://toolbelt.heroku.com/

Our app only needs a small change in order to work with Heroku. Open up the Gemfile and make the following change:

Remove: gem ‘sqlite3’
Add: gem ‘pg’

Now run:

bundle install

This will swap out the database from sqlite3 to Postgres (if you ran the initial Rails generator with Postgres as the database, this step is not necessary).

Now that everything is configured with your system, you can go back to your app. In the terminal enter in:

heroku create jdh-tasker

‘jdh-tasker’ could be any name (assuming it is not taking on the Heroku system). I always preface my Heroku apps with my initials to ensure I do not run into naming issues.

If you pushed up to the server right now you would get an error because we are using local environment variables in our config/application.yml file. However, Heroku does not know what the values represent since we are purposefully hiding them. Run the following commands to get the values on the server:

heroku config:set AWS_ACCESS_KEY_ID="Your access key"
heroku config:set AWS_SECRET_ACCESS_KEY="Your secret key"
heroku config:set AWS_BUCKET="Your production bucket name"

Now that everything is set up, including our environment variables, you can push the app to the server. Run:

git push heroku master

If that all pushed up successfully, it should give you the URL where the app will be located. Mine can be found at: https://jdh-tasker.herokuapp.com/

Before you go to the app, we first need to create the database on the server. Run:

heroku run rake db:migrate

Now go to your URL and you should see the site. If that all worked, congratulations! If you ran into any issues, make sure you went through all of these steps exactly.

Heroku add-ons

A nice bonus with using Heroku is that they have a laundry list of plugins/add-ons that can quickly add functionality to your application. Some of my favorites are:

– Heroku scheduler: this lets you easily schedule automated tasks to run in the background at scheduled intervals.
– PGBackups: with this installed, you can create snapshots of your database
– New Relic: with New Relic, you can remotely monitor your app’s performance
– Mandrill: a great mail service

Setting up a scheduled task

For this application, we will walk through how to create a scheduled task using the Heroku Scheduler add-on. To get started, run:

heroku addons:create scheduler

Now you can go to Heroku.com and login with your Heroku credentials. Once logged in, you can click on the app and you should see that the Heroku Scheduler has been added as an add-on. To configure it simply click on the “Heroku Scheduler” link and it will prompt you to add a new job. Here you can add a rake task and set up the frequency, and what day you want it to begin. Typically I will create a custom rake task, such as connecting to an API or updating values in the database, etc.

Advanced development

So where should you go from here? The Rails ecosystem is extremely large and you could spend decades trying to cover everything. Below are some of the top items that I work on regularly.

Testing

If you want to create production Rails applications, you will need to become fluent with automated testing. Many organizations will not even hire developers if they cannot integrate testing into their apps. Some of the key terms and libraries to research are:

– Rspec: Testing library/framework for Ruby – find out more here: http://rspec.info/
– TDD (Test Driven Development) – the principle of writing unit, functional, and integration tests, the RailsGuides has a full tutorial on how you can integrate TDD: http://guides.rubyonrails.org/testing.html
– Capybara: An acceptence test framework that lets developers mimic user behavior in the views – the Gem page is here: https://github.com/jnicklas/capybara

Microservices

There is great debate in the Rails community around the concept of microservices vs. monoliths. Microservices are essentially features of an application that can live independently from the rest of the application. For example, I am working with a team on a very large, mission-critical application that monitors fluid sensors for energy companies throughout the US at over 4,000 locations. The decision was made very early on that creating one large application would be a mistake and instead we were tasked with creating a number of smaller apps that all performed a single task. I built a notification engine that would call, email, and message users whenever a fluid sensor would go off. In a normal application my notification engine would ‘know’ all about the rest of the application, but with a microservice the app has nothing to do with the rest of the main app’s functionality. In fact, I built my app in such a way that it did not even matter what type of system it was connected to. It could have been a notification system for: fluid levels, a police task force, a trucking fleet manager, etc. I simply built an API with a series of endpoints that the other app called to create notifications.

It is my definition that a microservice is an application with a single piece of functionality that can work independently of any other application. You could be a Rails developer for your entire life and never need to build a microservice, but they are becoming more popular as of late and it would be beneficial to understand how they operate.

Gem development

While building out our application, we used a number of Gems. As a Rails developer it will become important for you to be able to create your own Gems and modify existing ones that need to be altered. One of my development clients is Eventbrite, and when I was tasked with building out a new application for them, I attempted to use a Gem to connect to their API. However, I discovered that the Gem was outdated and needed a number of changes. I was able to create a new version of the Gem (also called ‘forking’) and integrated the new version of the Gem to get the app up and running.

You can also build out Gems from scratch. If you have a feature or special generator that you feel would be important to use in multiple applications, sometimes it is a good idea to create your own library of Gems that you can utilize in any and all apps that you work in to help save you time and extra code. For information on how to create Ruby Gems, here is a good starting point: http://guides.rubygems.org/make-your-own-gem/