A Rails application template with the narralabs defaults. These defaults are optimized for development efficiency. It already includes things like haml
, simple_form
, rspec
, and shoulda-matchers
to name a few. Also includes tools that you will need in production like sitemap_generator
, rack_timeout
, high_voltage
and others.
It is built to be deployable after initial app creation. You should already have a production app and deployment environment from day 0. The recommended deployment environment is through Heroku but a second option is by using AWS Copilot and ECS Fargate.
Important
It is recommended that you deploy immediately after creating an app using the template. This will ensure that we do continuous deployment from the beginning of the application.
In order to use the rails application template, you need to have:
- At least ruby 2.7.4
- At least rails 7.0.2.3
Create a new rails app using the following:
rails new blog -m https://raw.githubusercontent.com/narralabs/thomas/main/template.rb
Create a new rails app using the template with Tailwind CSS:
rails new blog --css tailwind -m https://raw.githubusercontent.com/narralabs/thomas/main/template.rb
- Awesome Print for beautiful puts statements
- Devise for authentication
- Haml for beautiful HTML markups
- Simple Form for easier forms
- SitemapGenerator for generating sitemaps
- Sidekiq for processing background jobs
- Rack Timeout to abort requests that are taking too long
- Rubocop for static code analysis
- High Voltage for static pages
- Title for storing titles in translations
- RSpec for BDD testing
- FactoryBot for fixtures
- Timecop for time testing
- Shoulda Matchers for one-line matchers
- Brakeman for static analysis security vulnerability scanning.
After creating the app. It is highly recommended to:
- Add error monitoring. We suggest rollbar.
- Add performance monitoring. We suggest skylight.
- Run devise generator:
rails generate devise:install
. The devise gem is installed but we don't make assumptions on the auth structure.
The preferred deployment setup for this template is with AWS Copilot. To deploy using AWS Copilot:
-
Get your AWS Credentials and add to
~/.aws/credentials
[myprofile] aws_access_key_id=[AWS_ACCESS_KEY_ID] aws_secret_access_key=[AWS_SECRET_ACCESS_KEY] region=us-east-1
-
Use your AWS Credentials:
export AWS_PROFILE=myprofile
-
Create the app using copilot.
copilot init copilot env init --name production copilot env deploy --name production
-
Add the
SECRET_KEY_BASE
ENV variable:# Generate the secret key $ openssl rand -hex 64 SomeLongRandomString $ copilot secret init What would you like to name this secret? [? for help] SECRET_KEY_BASE What is the value of secret SECRET_KEY_BASE in environment production? [? for help] SomeLongRandomString
-
Add the
DATABASE_URL
ENV variable by creating an RDS database. Pick Postgres under the free tier plan to start.# Create a random db username and set this aside. $ cat /dev/urandom | LC_ALL=C tr -dc 'a-z' | head -c 14 RandomUsername # Create a random db password and set this aside. $ openssl rand -hex 64 RandomPassword # Create a random db name and set this aside. $ cat /dev/urandom | LC_ALL=C tr -dc 'a-z' | head -c 14 RandomDbName # Generate the POSTGRES_URL by concatenating the generated strings and put this aside: postgres://RandomUsername:RandomPassword@RDS_HOST/RandomDbName # Go to AWS Console RDS and create the database. # - IMPORTANT! Make sure to fill up the database name field or the database will not be created. # - IMPORTANT! Make sure to put the RDS database in the same subnet as the created AWS Copilot app. # - IMPORTANT! Make sure to create a new security group and name it APP_NAME-db-sg-ENV. e.g. narralabs-db-sg-production # - IMPORTANT! Make sure to add allow the inbound port 5432 in the created RDS security group. Allow from the security group created in copilot env to the RDS security group. $ copilot secret init What would you like to name this secret? [? for help] DATABASE_URL What is the value of secret DATABASE_URL in environment production? [? for help] postgres://RandomUsername:RandomPassword@RDS_HOST/RandomDbName
-
Deploy:
copilot deploy
. Watch the logs for a "Running" state and visit the URL if so. If not, inspect the task logs. -
Mount the domain
www.myapp.com
.Go to Route53 Add a A record targeting the ALB load balancer created from the deploy.
-
Setup SSL
1. Go to ACM (AWS Certificate Manager) 2. Add 2 certificates for the domain(s): myapp.com www.myapp.com 3. Validate the certificate and make sure "Status" is "Issued"
-
Add SSL redirect setup for the ALB load balancer.
1. Go to ELB 2. Find the ALB load balancer for the app 3. Add listener for HTTPS port 443 and forward request to TargetGroup 4. Remove listener for port 80 5. Add another listener for port 80 but redirect to port 443
-
Setup redirect from
myapp.com
->www.myapp.com
.1. Create a an S3 Bucket that is used for static hosting. Name the bucket by domain: myapp.com 2. Create a Cloudfront distribution targeting the S3 Bucket above. 3. Add "Alternate domain name (CNAME) - optional" in the Cloudfront for myapp.com 4. Point the Cloudfront distribution in Route 53
-
Add S3 config.
-
Add Cloudfront config.
- Create an app in Heroku.
- Get the "Heroku git URL" in the Settings->App Information tab of the app in Heroku.
- Add the remote in the app and name it production:
git remote add production HEROKU_GIT_URL_HERE
- Deploy the app:
git push production master
- Get the URL of the app under Settings->Domains app in Heroku.
- Add custom domain
- Setup SSL
- You now have a full-fledged production app
- Add AWS S3 for storage and AWS Cloudfront for performance.
1. Create an S3 bucket. We typically follow the naming structure #{DASHERIZED-DOMAIN}-assets-#{ENV}: narralabs-com-assets-production - Turn off "Block all public access" under Permissions->Block public access (bucket settings) - Enable ACL access by setting Object Ownership to "Bucket owner preferred" under Permisisons->Object Ownership - Edit the Bucket policy { "Version": "2012-10-17", "Statement": [ { "Action": "s3:ListBucket", "Principal": "*", "Effect": "Allow", "Resource": "arn:aws:s3:::narralabs-com-assets-production" }, { "Action": "s3:PutObject*", "Principal": "*", "Effect": "Allow", "Resource": "arn:aws:s3:::narralabs-com-assets-production/*" } ] } - Edit the ACL list and enable ACL 2. Create a CloudFront endpoint that uses the S3 bucket as origin. 3. Add the required ENV variables for asset_sync gem heroku config:add AWS_ACCESS_KEY_ID=xxxx heroku config:add AWS_SECRET_ACCESS_KEY=xxxx heroku config:add FOG_DIRECTORY=s3-bucket-name-here heroku config:add FOG_PROVIDER=AWS heroku config:add FOG_ASSET_HOST=//my-cloudfront-endpoint.net 4. Change config/production.rb asset_host config.asset_host = "http://assets.example.com" # to config.asset_host = ENV['FOG_ASSET_HOST'] 5. Redeploy and check that assets are being served by the CDN.
To develop and contribute to the project:
- Clone the project
- Install dependencies:
bundle install
- [ADD NEW GEMS OR CONFIG HERE]
- Run the makefile which creates the app named "blog" in the current dir:
make
- Check the output logs and inspect the
blog
app to see if the files and config are generated correctly