# Database Configuration
I set up my own account in the Amazon Hong Kong region, created a new RDS instance, only to find that the free t2.micro option is not available in the selection list. I had no choice but to choose the cheapest option, t3.micro. After inquiring with customer service, they mentioned that the Hong Kong region is a new region and needs confirmation from the local team. Billing has started two days ago, and there has been no response yet. Although the price of 0.03 dollars per hour is not expensive, it still is money. If the issue cannot be resolved, I might consider trying Oracle’s Always Free plan.
Above was a side note. Next, let’s talk about the pitfalls encountered during the database configuration.
A correct database.yml
configuration is a necessary condition for the app to successfully call the RDS instance. Initially, I configured database
, username
, password
, and host
, only to find that the program, although in production, was still using sqlite3
as the database.
Comparing with configurations found online, I realized that two lines were missing. Since my RDS is PostgreSQL, it requires additional configuration for adapter
and encoding
. Otherwise, Rails would default to the settings in database.yml
, where the specified database type is sqlite3
.
A correct database.yml
configuration example is as follows:
# config/database.yml
production:
<<: *default
# database: db/production.sqlite3
adapter: postgresql
encoding: unicode
database: <%= ENV['RDS_DATABASE'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOST'] %>
post: 5432
# Environment Variables
Initially, I used ~/.bashrc
for environment variables, directly adding export KEY=value
in the file, and then updating the environment with source ~/.bashrc
. However, it seems that Rails occasionally encounters issues reading these environment variables. Moreover, it is considered inadequate from a security perspective. So, I switched to using the dotenv gem. However, during my second deployment to the server, Rails could not read the environment variables correctly, and the environment even switched to development. This issue was intolerable, leading me to switch to using the figaro gem.
As usual:
# Gemfile
gem "figaro"
Run:
bundle install
bundle exec figaro install
Figaro will modify .gitignore
and create config/application.yml
. The purpose of modifying .gitignore
is to prevent sensitive information from application.yml
being transmitted to git. Therefore, we need to manually create an application.yml
on the server and fill in the environment variables.
# config/application.yml
production:
RDS_DATABASE: "postgresql://sadhuhuwd.aws.com/asdhuio"
RDS_PASSWORD: "ad69caf9a44dcac1fb28"
MAILER_EMAIL: "83ca7aa160fedaf3b350@gmail.com"
Then start the server, and Rails will be able to recognize the environment variables correctly.
# Rails Credentials
Starting from Rails 5.1, secret.yml
is no longer used to store the master key. Instead, it uses config/credentials.yml.enc
to store the encrypted master key, and config/master.key
to store the decryption key used to decrypt credentials.yml.enc
, ensuring the security of the key. In the production environment, if Rails cannot find the decryption key, the following errors may occur.
# Possible Error 1
ActiveSupport::MessageEncryptor::InvalidMessage
# Possible Error 2
Please run `rails credentials:edit`
This issue troubled me for almost an entire day. Every attempt to deploy to Elastic Beanstalk ended in failure. Finally, StackOverflow user littleforest provided two solutions.
# Solution One
Run in the local environment:
rails credentials:edit
Copy the secret_base_key that appears and add SECRET_KEY_BASE=<content you just copied>
to your server environment variables.
# Solution Two
I ultimately chose this solution.
Run in the local environment:
rails credentials:edit
Then open config/master.key
and copy the content.
Add RAILS_MASTER_KEY=<content you just copied>
to the server’s environment variables.
It is still recommended to manage ENV using the figaro gem mentioned earlier.
# Webpacker Compiling
When using Asset Pipeline, I encountered an issue where I couldn’t guarantee that scss files were loaded in order. This caused errors when calling bootstrap variables across multiple files. Since Webpacker is gaining popularity, I reluctantly followed the tutorial to place scss files in app/javascript/stylesheets
and use application.js
to load scss.
However, upon opening the rails server, I received an error on the webpage resembling:
could not find application in manifest.json
This exposed my knowledge gap. After researching, I found that Webpack, as the name suggests, has a packing process. Webpacker bundles resource files and by default saves them in the app/public/packs
folder, generating a manifest.json
to indicate to Rails which files in the packs
folder need to be loaded. Since we didn’t set up Webpacker to compile css, Rails couldn’t find the index of css files in the manifest. Therefore, configuration is needed in config/webpacker.yml
.
Configure the following in defaults and development projects:
# config/webpacker.yml
default: &default
...
# Reload manifest.json on all requests so we reload the latest compiled packs
cache_manifest: false
# Extract and emit a css file
extract_css: true
...
development:
<<: *default
compile: true
...
extract_css
ensures Webpacker generates compiled css, compile
indicates compiling before starting the server, and cache_manifest
caused me to struggle for hours. Accidentally setting it to true prevented the web page from updating whenever css was modified, so it requires special attention to ensure it is set to false.
During development, you can use the command bin/webpack-dev-server
to open the compiling server. Webpacker will detect changes to resource files and immediately generate manifest.json
. Even better, it can automatically refresh the browser to apply changes.
# Local Precompilation
During the process of deploying the App to EC2, I discovered that the rails server
command itself does not precompile resource files. Additional running of rails assets:precompile
is required. However, on a 1G1C server, running precompile for half an hour still couldn’t complete. Therefore, I had to consider compiling locally.
After running rails assets:precompile
locally, remove or comment out the following path in .gitignore
:
# /public/packs
This way, when pushing, the precompiled files can be uploaded together.
20200608#EDIT: After rebuilding the EC2 instance, I found that simply enabling the Unlimited feature of the instance allowed the server to handle the sudden increase in performance demand. Compilation now takes only a few minutes, so I no longer need to precompile locally.