Setting Up a New Rails App

Postgres, Bootstrap, Spree, MDBootstrap, Devise, there's a lot to think about...

Tags: Ruby on Rails, Setup

Back to Blogs

Prerequisites:

gem install rails -v 5.2.2

gem install bundler

brew install imagemagick

And now the app:

rails _5.2.2_ new appName --database=postgresql

Now you cd into appName...

Github Repository Setup

git init
git add .
git commit -m "First Commit"
git remote add origin git@github.com:yourName/appName.git
git push -u origin master

Gemfile

   source 'https://rubygems.org'
   git_source(:github) { |repo| "https://github.com/#{repo}.git" }

   ruby '2.5.0'

   gem 'rails', '~> 5.2.0'
   gem 'sass-rails', '~> 5.0'
   gem 'uglifier', '>= 1.3.0'
   gem 'coffee-rails', '~> 4.2'
   gem 'jbuilder', '~> 2.5'
   gem 'jquery-rails'
   gem 'jquery-ui-rails'
   gem 'devise'
   gem 'sprockets-rails'
   gem 'bcrypt', '~> 3.1.7'
   gem 'gon'

   gem 'mini_magick'
   gem 'aws-sdk' , '~> 3'
   gem 'aws-sdk-s3', require: false

   gem 'bootstrap', '~> 4.1.3'
   gem 'bootsnap'
   gem 'simple_form'
   gem 'font-awesome-rails'
   gem 'font-awesome-sass'
   gem 'font_awesome5_rails'

   gem 'friendly_id', '~> 5.2.0'
   gem 'acts-as-taggable-on', '~> 6.0' #must be this version for Rails5
   gem 'invisible_captcha'
   gem 'kaminari'
   gem 'kaminari-bootstrap'
   gem 'tinymce-rails'

   gem 'figaro'
   gem 'high_voltage', '~> 3.1'
   gem 'acts_as_list'

   gem 'puma', '~> 3.11'
   gem 'puma_worker_killer'
   gem 'rack-tracker'
   gem 'dotenv-rails'
   gem 'faraday'
   gem 'scout_apm'

   group :production do
     gem 'pg', '~> 0.20.0'
   end

   group :development do
     gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
     gem 'pry-rails'
     gem 'web-console', '>= 3.3.0'
     gem 'listen', '>= 3.0.5', '< 3.2'
     gem 'spring'
     gem 'spring-watcher-listen', '~> 2.0.0'
     gem 'binding_of_caller'
     gem 'better_errors'
   end

And the terrifying bundle install.

Application.css (Change to SCSS)

*
 *= require_tree .
 *= require_self
 */

  @import 'bootstrap';
  @import 'mdb/mdb';
  @import 'font-awesome';
  @import 'font_awesome5_webfont';
  @import 'font_awesome5.css';



 /*-----------------------------
 -------------------------------
 ------------COLORS-------------
 -------------------------------
 -------------------------------
 -----------------------------*/

Application.js

//= require jquery3
//= require jquery_ujs
//= require jquery-ui
//= require popper
//= require bootstrap
//= require rails_sortable
//= require activestorage
//= require font_awesome5
//= require tinymce

Add MDBootstrap

Add this mdb_framework.js to your JS folder:

//= require mdb/mdb

Add Rails.application.config.assets.precompile += %w( mdb_framework.js ) to your config/initializers/assets.rb file.

And the files themselves to your vendor folder.

Finally, add a basic application.html.erb with the appropriate includes.

<!DOCTYPE html>
<html>
  <head>
    <title>
      <%= if content_for?(:title) then yield(:title) + ' | ' end %>
      Site Name
    </title>
    <%= if content_for?(:head) then yield(:head) end %>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= include_gon %>
    <%= stylesheet_link_tag    'application', media: 'all' %>
    <%= javascript_include_tag :application %>
    <%#= favicon_link_tag %>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- reCAPTCHA -->
    <script src="https://www.google.com/recaptcha/api.js" async defer></script>

    <!-- favicons -->

  </head>

  <body>


    <div class="non-footer">
      <%= render 'layouts/navbar' %>
      <%= render 'layouts/notifications' %>

      <%= yield %>
    </div>

    <%= render 'layouts/footer' %>

    <%= javascript_include_tag 'mdb_framework'%>

    <%= yield :additional_js %>
  </body>
</html>

And don't forget to add partials for _footer, _navbar, and _notifications. In fact...

Notifications

<!-- flash notice area -->
  <div class="flash-notice-area">
    <% if flash[:notice] %>
      <div class="alert alert-success">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        <%= flash[:notice] %>
      </div>
    <% elsif flash.now[:alert] %>
      <div class="alert alert-danger">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        <%= flash.now[:alert] %>
      </div>
    <% elsif flash[:warning] %>
      <div class="alert alert-warning">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        <%= flash[:warning] %>
      </div>
    <% end %>
  </div>
<!-- flash notice area -->

Spree Setup (if you're into that kind of thing)

Add to gemfile:

gem 'spree', '~> 3.7.0'
gem 'spree_auth_devise', '~> 3.5'
gem 'spree_gateway', '~> 3.4'

And the terrifying bundle install.

And then the generators:

rails g spree:install --user_class=Spree::User
rails g spree:auth:install
rails g spree_gateway:install

And that works so far. Changed / to /store in my routes.rb so the store isn't the homepage.

Create Your Database

With a rake db:create db:migrate.

And Some Actual Pages

And let's rails g controller Home index so we have something to look at.

Oh yeah, and this in routes.rb:

   get 'home/index'
   root 'home#index'

Added some stuff in the index.html.erb goes some bootstrappy stuff to test, and it seems to be working so far!

Static Pages with High Voltage

Add a folder called pages to your views:

$ mkdir app/views/pages
$ touch app/views/pages/about.html.erb

And to get rid of the /pages/ in the url:

The usual

gem 'high_voltage', '~> 3.1'

and

bundle install

then

# config/initializers/high_voltage.rb
HighVoltage.configure do |config|
  config.route_drawer = HighVoltage::RouteDrawers::Root
end

You can link to it like this:

<%= link_to 'About', page_path('about') %>

Setting up Devise

Install it:

$ rails g devise:install

Add this to your development.rb environment:

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

And this to your production.rb file:

  config.action_mailer.default_url_options = { :host => "yoursitehere.com" }

And create a model (usually USER):

$ rails g devise User

Before you do rake db:migrate you can add any custom fields you want for your model into the generated migration. Usually something like this:

      t.string :first_name
      t.string :last_name
      t.string :membership, default: "Free"
      t.boolean :admin, default: false

And if you do add custom fields don't forget to add them to a registrations_controller.rb like this:

class RegistrationsController < Devise::RegistrationsController

  private

  def sign_up_params
    params.require(:user).permit(
      :first_name,
      :last_name,
      :email,
      :phone,
      :admin,
      :password,
      :password_confirmation
    )
  end

  def account_update_params
    params.require(:user).permit(
      :first_name,
      :last_name,
      :email,
      :phone,
      :admin,
      :password,
      :password_confirmation,
      :current_password
    )
  end
end

And replace the generic devise routes like this:

devise_for :users, :controllers => { registrations: 'registrations' }

Setting Up Heroku Staging and Production Servers

Follow the Heroku Documentation

Setting Up Figaro (Gem)

You already have the gem in the gemfile, so just run bundle exec figaro install to get your config/application.yml file.

Provisioning Sendgrid for Email (with Heroku)

Run this bad boy: heroku addons:create sendgrid:starter -a yourappname

And then get your variables with heroku config:get SENDGRID_USERNAME -a yourappname and heroku config:get SENDGRID_PASSWORD -a yourappname.

Don't forget to put your sendgrid username and password into your Figaroconfig/application.yml file.

And finally, put this in your environment.rb:

ActionMailer::Base.smtp_settings = {
  :user_name => ENV["SENDGRID_USERNAME"],
  :password => ENV["SENDGRID_PASSWORD"],
  :domain => 'websitename.com',
  :address => 'smtp.sendgrid.net',
  :port => 587,
  :authentication => :plain,
  :enable_starttls_auto => true
}

Setting Up Active Storage with AWS S3

Note: All this is pretty much straight out of the documentation, but I wanted it all in one place, so I'll reiterate.

Start by setting up your bucket on S3 (and no dashes in the bucket name...I learned that one the hard way).

Make sure you have gem "aws-sdk-s3", require: false in your Gemfile and bundle install.

Take note of your bucket and then add (or uncomment) this block in your storage.yml file:

# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
amazon:
  service: S3
  access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>
  region: us-west-1
  bucket: appnamehere

Don't forget to add your information to your Figaro application.yml file:

development:
  AWS_ACCESS_KEY_ID: ***keygoeshere***
  AWS_SECRET_ACCESS_KEY: ***keygoeshere***

production:
  AWS_ACCESS_KEY_ID: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  AWS_SECRET_ACCESS_KEY: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

Change the appropriate lines in your environments. So...

In development.rb do:

  config.active_storage.service = :local

In production.rb do:

  config.active_storage.service = :amazon

In test.rb do:

  config.active_storage.service = :test

One thing that weirdly is NOT in the documentation:

bin/rails active_storage:install:migrations
bin/rails db:migrate

And then you can add it to your model with a:

class User < ApplicationRecord
  has_one_attached :avatar
end

And put it in your controller create/update with this:

    if params[:user][:avatar].present?
      @user.avatar.purge
      @user.avatar.attach(params[:user][:avatar])
    end

...or whatever your case may be and add it to your params list.

Then you can add something into your form:

<div class="form-row mt-4 text-left">
   <div class="col-12">
      <label>Upload an Avatar</label>
      <%= f.file_field :avatar %>
   </div> <!-- col-12 -->
</div> <!-- form row -->

Refer to images like this:

<% if current_user.avatar.attached? %>
    <%= image current_user.avatar %>
<% end %>

Back to Blogs