I decided to take a look at the latest version of Ruby on Rails version 5.1. It has a lot of new features that is supposed to catch up with the latest web app development trends. I was primarily interested in using ReactJS with Rails and was surprised to learn that Rails 5.1 includes webpacker. The webpacker gem allows you to manage your Javascript app libraries in your rails app in a more friendly way than using the asset pipeline.
What does this mean for rails developers? It means that you are now able to integrate the latest Javascript development libraries such as React, Angular, and Vue in your app in a conventional manner which is the reason I love rails. Having your javascript development outside of the asset pipeline is less clumsy and reduces the number of times you need to restart your rails app when making code changes. More information can be found at https://github.com/rails/webpacker and http://weblog.rubyonrails.org/releases/.
This all sounds great and I set forth to create a new rails app to try out Rails 5.1. I knew I was going to run into some road blocks because my development environment is using Docker containers. I like Docker because it keeps all of my projects separate and I can start and stop a container depending on which project I am working on. If you haven’t checked out Docker yet I recommend taking a look at https://www.youtube.com/watch?v=NEdDa3Zqu7s. The problem with Docker is that you cannot access the container unless it is up and running. If you have an error in your configuration or some package did not get installed properly, you will not be able to access the container because starting up the container will fail.
My first issue was with the version of nodejs that is required for the webpacker gem. I was able to get my db and rails containers created but the rails container had an old version of nodejs. My Dockerfile looked like this originally:
# Create container for Ruby FROM ruby:latest MAINTAINER David Oshiro <david@davidoshiro.com> ARG APP_NAME ARG APP_PORT # Install packages RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs RUN mkdir -p /usr/share/www/$APP_NAME WORKDIR /usr/share/www/$APP_NAME # Check to see if server.pid already exists. If so, delete it. RUN test -f tmp/pids/server.pid && rm -f tmp/pids/server.pid; true ADD Gemfile . ADD Gemfile.lock . # Bundle RUN bundle install ADD . .
On line 9 you can see that I am installing nodejs. But the nodejs version installed was v0.10!!! I not only needed nodejs but yarn as well so I made the following changes:
# Create container for Ruby FROM ruby:latest MAINTAINER David Oshiro <david@davidoshiro.com> ARG APP_NAME ARG APP_PORT # Install nodejs RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - # Install yarn RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list # Install packages RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn RUN mkdir -p /usr/share/www/$APP_NAME WORKDIR /usr/share/www/$APP_NAME # Check to see if server.pid already exists. If so, delete it. RUN test -f tmp/pids/server.pid && rm -f tmp/pids/server.pid; true ADD Gemfile . ADD Gemfile.lock . # Bundle RUN bundle install ADD . .
My docker-compose.yml looks like this:
version: '3' services: db: image: mariadb:latest volumes: - ./.data/db:/var/lib/mysql ports: - 3306:3306 env_file: .env app: build: context: . args: - APP_NAME - APP_PORT command: rails server --port 3000 --binding 0.0.0.0 volumes: - .:/usr/share/www/$APP_NAME ports: - $APP_PORT:3000 depends_on: - db env_file: .env
As you can see i am using environment variables that are stored in a .env file. I am also mounting my local current folder as /user/share/www/$APP_NAME in the container. This will allow me to edit the code on my local filesystem. The database is also mounted from the local .data folder. Using volumes to mount local folders in the containers is essential when using Docker as your development environment.
I build my container using the following:
docker-compose build
Once my container is built, I can create my rails app via:
docker-compose run app rails new . --database=mysql --webpack --skip-coffee-script --skip-turbolinks
Basically, I am telling Docker to run the command “rails new” in the “app” container. It will generate the rails file structure in the current folder.
Next, I need to run ‘bundle install’ to install the gems that the new rails app needs:
docker-compose build
Finally, I can implement Facebook’s ReactJS javascript libraries:
docker-compose exec app rake webpacker:install docker-compose exec app rake webpacker:install:react