My Takeaway from Reading Sometimes you Win, Sometimes you Learn

Book: Sometimes you Win, Sometimes you Lean
Author: John C. Maxwell

My takeaway from this book had nothing to do with it’s premise: learning from your mistakes. Instead my takeaway had to do with writing. Specifically make sure your audience can relate to your example.

One of the first examples of making mistake in the book is when the author accidentally brings a loaded gun to the airport. You can read all the details here but in summary he was giving a handgun as a gift while on a trip. He flew home on a private plane where, after they landed, the pilot showed him how to load the gun (this part is only in the book). He put the gun in his briefcase and when he got home forgot about it. His next trip, on a public plane, he took the briefcase with the loaded gun to the airport. You can figure out what happened when he got to security.

After the incident the author appears to suffer no loss from the incident aside from some embarrassment. No charges, monetary loss, or loss of reputation. It is also hard to figure out what he learned from the incident.

I kept wondering who was the target audience for that example? It clearly was not for me but I couldn’t even picture anyone I know relating to it. It’s a shame that example was the at the beginning of the book as later examples are much better. Examples where I felt the lose of the person suffered and the lessons learned as they recovered from their loss.

So my takeaway is to make sure I keep my audience in mind when writing, especially for my examples. Will the reader be able to picture themselves in the example? If not themselves will can the picture someone else? Will the example trigger the emotion(s) I’m hoping for? If I’m writing a technical example what level of developer is it targeted too?

Now I just need to think about who I wrote this blog post for…

Posted in Takeaways | Tagged | Comments Off on My Takeaway from Reading Sometimes you Win, Sometimes you Learn

Today I Learned About GitHub’s Dependabot

Recently I created a CI build for the Introduction to ORM for DBAs presentation example code. One of the reasons I picked this code base was so I could try out Dependabot for the security alerts I’m getting.

Security alert in GitHub.

The security alert is for the ASP.NET Core NuGet package. The same issue is listed multiple times because the code is duplicated several times for the various steps in the example.

List of Security Alerts in GitHub

Viewing more details about the error I see it recommends upgrading the package to 2.0.9 or later.

Security Alert Details

Let’s try the automatic fix and see what happens.

This will create a pull request and kick off an automated build in the Azure Pipeline for this project.

That is no good. It appears that I have a direct reference to EntityFrameworkCore.Design in my project. Let me go look.

There it is. Let’s update it to the latest version of 2.0.x. Now that I think about it I wonder if we can just remove it? Let’s save that for a later commit.

It builds and run on my local machine. Commit out changes and see what the CI build says.

Now we can squash and merge this commit and we are all done. At least for example 1 of 10. I was really hoping Dependabot would auto-magically fix all the broken dependencies but it appears I have some manual work to do. Oh well. Maybe it will work better next time.

P.S. – Robot Rock.

Posted in Today I Learned | Tagged , , , | Comments Off on Today I Learned About GitHub’s Dependabot

Notes on Fixing Ubuntu 18.04 VM not Booting

Some notes so I remember how to fix this problem if it happens again and I don’t waste a bunch of time figuring it out right before a customer production release. Not a great start to my day.

This issue happened to me many moons ago when I first upgraded to VirtualBox 6 and Ubuntu 18. This is the second time so I better write down what I did so I hopefully remember if it happens a third time.

The problem is my Ubuntu VM boots but freezes before getting to the login screen. It will either stay purple but sometimes goes black.

The problem occurred after upgraded the Ubuntu 18.04 guest to kernel 4.15.0-52. I also installed updates on my Windows 8.1 host (I know, I need to upgrade to Windows 10, it’s on the list) but I don’t think that had anything to do with the problem. No recent updates to VirtualBox.

The first step in trying to fix this problem is to boot in safe mode. If you don’t know to boot into safe mode in Ubuntu hold down the left-shift key.

You won’t be able to run any of the diagnostics because VirtualBox can’t remount the file systems as read only.

Just choose resume to continue booting in safe mode which will hopefully show the login screen but with the VirtualBox Guest Additions graphic drivers disabled. This means you will get a 800 x 600 screen that can’t be resized.

Now try to re-install the VirtualBox Guest Additions.

Shut down and restart the VM and see what happens. If it boots then you are good to go. If it does not boot, which it didn’t for me, you can change the VirtualBox graphics controller. Do this by opening up the settings for your VM and select Display.

Most likely your graphics controller will be VMSVGA if you are running a newer version of Linux. Change it to VBoxSVGA and reboot. If it’s already at VBoxSVGA try VMSVGA instead. You can read about the differences between the settings here.

Start up the VM and hopefully it won’t hang.

I’m assuming this graphics driver problem will be fixed by a future release of Ubuntu and/or VirtualBox but since this is the second time it’s happened to me it would not surprise me if it happens again.

I currently don’t notice any difference between VMSVGA and VBoxSVGA but it’s only been an hour or so.

P.S. – I haven’t seen Into the Spider-verse movie yet but my daughter has and really enjoyed it. I really like the animation style, assuming the music video uses clips from the movie.

Then you’re left in the dust, unless I stuck by ya
You’re a sunflower, I think your love would be too much
Or you’ll be left in the dust, unless I stuck by ya
You’re the sunflower, you’re the sunflower

Posted in Notes, Support | Tagged , , | Comments Off on Notes on Fixing Ubuntu 18.04 VM not Booting

Today I Learned How to Setup Azure Pipelines CI

Our last EDMUG meetup was an excellent presentation about Azure DevOps. Azure DevOps reminds me of GitLab where it is more then just continuous integration (CI). It includes issues tracking, repositories, and continuous delivery. All pretty standard stuff.

However, one thing did jump out at me. The fact it had build built in images you could use to run the build on. Build images with Visual Studio pre-installed. They also have macOS X Mojave! No need to create you own build runner, either VM or Docker, like you do with so many other CI tools.

I don’t think using a 3rd party build image is the answer for everything. There are cases where I would want more control over the build image but for the example code I use for presentations the default image is good enough. No need for me to create and maintain a build image.

For this example I’m going to use my Introduction to ORM for DBAs presentation code. It’s a good project to start with as the presentation code is simple and does not have many dependencies. I also want to get an automated build working before trying GitHub’s Dependabot to auto-magically update dependencies for the presentation code.

Once I created my Azure DevOps account I then created the Introduction to ORM for DBAs project. For this new project the first thing I do is disable all the features but the Pipelines as I only need CI, not Git, bug tracking, etc.

Next I created the Pipeline.

I was prompted where the code is stored. In my case it’s stored in GitHub. I also was prompted to give Azure Pipelines access to GitHub which I did.

Now need to pick the repository and allow Azure Pipelines to access that repository.

Pipelines now presents some default builds. I picked the ASP .NET Core.

Then generates a reasonable default build file. This file will be stored in the root of you project with the name azure-pipelines.yml.

# ASP.NET Core (.NET Framework)
# Build and test ASP.NET Core projects targeting the full .NET Framework.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core

trigger:
- master

pool:
  vmImage: 'windows-latest'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- task: NuGetToolInstaller@0

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: VSTest@2
  inputs:
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

Overall I like the defaults that where picked. Let’s examine this scrip in more details and see what it is doing. First it triggers a build on any changes to the master branch. I wonder if it will also build on pull requests?

trigger:
- master

Next it lists the image the build will be preformed on. The ‘windows-latest‘ is VS 2019 on Windows Server 2019. Works for me.

pool:
  vmImage: 'windows-latest'

Next it defines some variables to use in the actual build. I like the fact it finds all the solution files as the example project has 10 separate solutions for each of the steps.

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

Next are the actual build steps with the first being install the NuGet packages. Nothing special here.

- task: NuGetToolInstaller@0

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

After that is the step to compile. In this case compile is done using Visual Studio. I wonder why Visual Studio was picked instead of just building using .NET Core command line? Maybe so it can produce the deploy packages?

I think I can remove building the deploy packages as this build is just for an example and will never be released. For now let’s just leave it and see what happens.

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

The final step is running the tests. I don’t have any tests for my example so I’ll be removing this step but for now just leave it and see what happens with the first build.

- task: VSTest@2
  inputs:
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

Let’s try to build with the default file and see what happens.

That is no good. Digging into the error message it appears that my application uses .NET Core 2.0 but it’s not installed on the image. We can fix this by installing .NET Core 2.0 using the DotNetCoreInstaller command as our first step.

When specifying the version of .NET Core it wants the SDK version, not the public .NET Core version. In my example I’m using the out of support .NET Core 2.0 but I would like to install the latest version of it. Using this handy chart I can see it’s SDK version 2.1.202.

Let me try the build now and see what happens.

That looks better. The final couple steps is to remove the build steps we don’t need, such as tests, and also don’t bother creating the deployment packages. I also changed the image to windows-2019 instead of latest which should prevent the build from magically failing if latest changes to VS 2020 or a different version of Windows. The final build script now looks like:

# ASP.NET Core (.NET Framework)
# Build and test ASP.NET Core projects targeting the full .NET Framework.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core

trigger:
- master

pool:
  vmImage: 'windows-2019'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
# Install .NET 2.0.9.  Not supported anymore but
# is what we want to upgrade to too to fix the security
# issues.  After the build is working we will upgrade
# to a support .NET version.
- task: DotNetCoreInstaller@0
  inputs:
    version: '2.1.202'

- task: NuGetToolInstaller@0

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

When this build runs there won’t be any warnings for the tests because they have been removed.

That was relatively painless. If you are curious you can find the public pipeline build here.

P.S. – For some reason I find Angels and Airwaves great programming music for getting into the zone and their latest song, Rebel Girl, is no exception.

D-d-do you wanna go back to where we started?
Back before we were broken hearted?

Posted in Today I Learned | Tagged , | Comments Off on Today I Learned How to Setup Azure Pipelines CI

Introduction to ORMs for DBAs: Part 8 – Create Game Players CRUD – Part 1

I gave the Introduction to ORMs for DBAs presentation at SQL Saturday 710 but it didn’t go as well as I would have liked (i.e. I had trouble getting my demo working).  Since the demo didn’t work live I thought I would show you what was supposed to happen during the demo.  You can find the slides I showed before the demo here.

The goal of this demo is create a basic website that tracks the games you and your friends play and display wins and losses on the home page.  I used a MacBook Pro for my presentation so you will see Mac screen shots.  That said the demo will also work on Windows.

In the previous post we created the GamePlayers table.  The GamePlayers table stores who played a game and if they won or lost.  In this post we will start creating the CRUD method pages for the GamePlayers table.

If you skipped the previous post but want to follow along open up 08-Create Game Players CRUD. Then run the migrations to create the Player, Games, GameResultTypes, GamesPlayed, and GamePlayers tables in the database.  Your database should be similar to the below screen shot.  The migration IDs can be different but the tables should exist.

Previously when adding CRUD methods we used commands to create scaffolding for index, create, view, edit, and delete pages. This makes sense when you have a simple model, such as players or games and don’t require a fancy interface. For games a player has won or lost it would be nice to have a fancier interface. Actually, it would be nice if you could edit the players that took part in a game in the Games Played page. Some like:

We can’t use scaffolding to build this interface, we have to do it the old fashioned way. We will keep our workflow simple. When a user choose the create a new Game Played we take them to the Game Played Create page where they can enter the game and date it was played.

When the user clicks the Create Button instead of redirecting them to the Games Played Create Page we will direct them to the Gamed Played Edit page where they can add players to the game and who won or lost. To do this we need to open up the GamesPlayedController and find the Post Create method which looks like the below.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,GameId,DatePlayed")] GamePlayed gamePlayed)
{
    if (ModelState.IsValid)
    {
        _context.Add(gamePlayed);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    ViewData["GameId"] = new SelectList(_context.Games, "Id", "Name", gamePlayed.GameId);
    return View(gamePlayed);
}

Update the redirect so it goes to the Edit page instead of the Index. Instead of:

return RedirectToAction(nameof(Index));

Change it too:

return RedirectToAction(nameof(Edit), new {id = gamePlayed.Id)};

Test by running the application and clicking on the button and you should be redirected.

That works. The next step is let the user enter some players as outlined in our mockup at the top of this post. Let’s start by adding the controls to add players to an existing game. Do this by opening the Games Played Edit page (Views/GamesPlayed/Edit.cshtml) and adding the following:

<div class="col-md-4">
        <form asp-action="CreateGamePlayer">
            <input type="hidden" id="GamePlayedId" name="GamePlayedId" value="@Model.Id">
            <div class="form-group">
                <label class="control-label">Player</label>
                <select id="PlayerId" name="PlayerId" class="form-control" asp-items="ViewBag.Players"></select>
            </div>
            <div class="form-group">
                <label class="control-label">Results</label>
                <select id="GameResultTypeId" name="GameResultTypeId" class="form-control" asp-items="ViewBag.GameResults"></select>
            </div>
            <div class="form-group">
                <input type="submit" value="Add Player" class="btn btn-default">
            </div>
        </form>
    </div>

If you run the application now you will see the controls but no data in the drop-down lists. Also the player controls will be on the left when we want the on the right. That will be fixed later.

Lets get some data in the drop-downs. If you look at the code in the Games Played Edit there are placeholders for the drop-down data in the ViewBag called ViewBag.Players and ViewBag.GameResults. To get data into the ViewBags open up the GamesPlayedController and find the Get Edit method.

Notice we already load data for the Game drop-down? It’s this line:

ViewData["GameId"] = new SelectList(_context.Games, "Id", "Name", gamePlayed.GameId);

Let’s add a couple more lines to load the data for the Player and Results drop-downs. If we where writing SQL statements the queries would be simple. Get all the players and all the game result types (i.e. win, lose, etc).

Select * From Players;
Select * From GameResultTypes;

Since we are using Entity Framework ORM we write a query to get all records from a table as:

_context.Players

We combine the ORM lookup with a helper method to populate the drop-down and we get:

ViewData["Players"] = new SelectList(_context.Players, "Id", "Name");
ViewData["GameResults"] = new SelectList(_context.GameResultTypes, "Id", "Type");

Now when you run the app the drop-downs should be populated.

The Add Player button still does nothing so lets fix that. Notice the in code we added to Games Played Edit view there is a form tag. In the form tag is the action that will executed when the Add Player button is clicked. In this case the CreateGamePlayer method will be called on the GamesPlayedController. The button does nothing because that method does not exist yet so lets create it.

[HttpPost]
public async Task<IActionResult> CreateGamePlayer([Bind("GamePlayedId,PlayerId,GameResultTypeId")] GamePlayer gamePlayer)
{
    _context.Add(gamePlayer);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Edit), new { id = gamePlayer.GamePlayedId});
}

The Bind("GamePlayedId,PlayerId,GameResultTypeId")populates the gamePlayer argument with only the listed arguments. That prevents malicious users from submitting parameters we might not want, such as the ID field.

The first two lines of the method insert the new GamePlayer record. The first statement queues new GamePlayer record to inserted.

_context.Add(gamePlayer);

The second line saves all the changes contained in the context. In this case it’s just the new GamePlayer record.

await _context.SaveChangesAsync();

The final line redirects us back to the Games Played Edit page.

return RedirectToAction(nameof(Edit), new { id = gamePlayer.GamePlayedId });

Try it out and make sure new results are added to the database. Since we currently don’t show adding new game players on the page we need to check the database.

This post is getting long and this seems like a good place to stop. In the next post we will finishing creating the user interface and CRUD methods.

If you got stuck you can find completed Part 8 here.  If you have any questions or spot an issue in the code I would prefer if you opened a issue in GitHub but you can e-mail (chris.cumming@saturdaymp.com) me as well.

Posted in Introduction to ORMs for DBAs, Software Development | Tagged , , , , , , | Comments Off on Introduction to ORMs for DBAs: Part 8 – Create Game Players CRUD – Part 1

My Takeaway from Reading When

When: The scientific Secrets of Perfect Timing

Book: When: The Scientific Secrets of Perfect Timing
Author: Daniel H. Pink

Any book that promotes napping is a win for me. These days it’s easy for me to catch a couple ZZZs as I work from home. When I was an employee or working at a clients site I would sometimes have an “errand” to run in the afternoon. An “errand” that involved driving to secluded place, tilting the seat back, and inspecting the inside of my eyelids for 20 minutes.

Aside from taking more naps my main takeaway from this book is to force start, middle, and ends. At least the good parts of starting, ending, and reaching the half-way points. You know, the old advice about breaking up a long project or task into smaller bits. Not something I didn’t already know but still good to be reminded of.

When also brought up the importance of the middle. Not just middle life but also the middle of a project or a task. Acknowledging the middle could be useful when you are stuck but it does not make sense to force and end/start. According to When most of the work on task gets done after the halfway mark and this holds true for short or long tasks.

Finally the last thing from When I’ll try to incorporate into my life is starting something important on good start days. Days like the start of the month, start of the week, after a holiday, anniversary of a life event, etc.

Posted in Takeaways | Tagged , | Comments Off on My Takeaway from Reading When

Thank you for Attending my SQL Saturday 840 Presentation – Create a Time Travelling Database

Thank you to everyone who attended my SQL Saturday 840Create a Time Travelling Database” presentation. I enjoyed your questions and the discussion after the presentation.

If you have any further questions feel free to reach out to me at chris.cumming@saturdaymp.com or @saturdaymp. I can also be found on the DevEdmonton and Legacy Code Rocks Slack channels.

Multiple Timelines

More resources about temporal databases:

P.S. – It was toss up between the below song and Rocky Horror Picture Show Time Warp. Guess I’m in a melancholy mood on this snowy day. Yes it is snowing on April 30th in Edmonton.

But there never seems to be enough time
To do the things you want to do, once you find them
I’ve looked around enough to know
That you’re the one I want to go through time with

Posted in Uncategorized | Comments Off on Thank you for Attending my SQL Saturday 840 Presentation – Create a Time Travelling Database

Introduction to ORMs for DBAs: Part 7 – Create GamePlayers Table

I gave the Introduction to ORMs for DBAs presentation at SQL Saturday 710 but it didn’t go as well as I would have liked (i.e. I had trouble getting my demo working).  Since the demo didn’t work live I thought I would show you what was supposed to happen during the demo.  You can find the slides I showed before the demo here.

The goal of this demo is create a basic website that tracks the games you and your friends play and display wins and losses on the home page.  I used a MacBook Pro for my presentation so you will see Mac screen shots.  That said the demo will also work on Windows.

In the previous post we created the GamesPlayed table and CRUD methods.  The GamesPlayed table stores when a game was played but it does not store who played the game.  In this post we will create the GamePlayers table to store who played the game and, more importantly, who won.

If you skipped the previous post but want to follow along open up 07-Create Game Players Table. Then run the migrations to create the Player, Games, GameResultTypes, and GamesPlayed tables in the database.  Your database similar to the below screen shot.  The migration IDs can be different but the tables should exist.

In this post we will create the last table the GamePlayers. It’s the table that tracks which players where involved with a game and if they won or loss.

Game Tracker ERD

As usual we start with the model. The only thing different about this model is it joins three other tables so had three foreign keys. Remember to add a foreign key in Entity Framework you add the ID and the Class.

using System.ComponentModel.DataAnnotations.Schema;

namespace SaturdayMP.GameTracker.Models
{
    [Table("GamePlayers")]
    public class GamePlayer
    {
        public int Id { get; set; }

        public int GamePlayedId { get; set; }
        public GamePlayed GamePlayed { get; set; }

        public int PlayerId { get; set; }
        public Player Player { get; set; }

        public int GameResultTypeId { get; set; }
        public GameResultType GameResultType { get; set; }
    }
}

You also need to add the other side the foreign key to the existing models. First the GamePlayed model:

public ICollection<GamePlayer> GamePlayers { get; set; }

Then the Game model:

public ICollection<GamePlayed> GamesPlayed { get; set; }

Finally the GameResultType model: ….Actually we won’t add the reference relationship to the GameResultType. This is to prevent a common mistake with ORMs where we accidentally load a bunch of records.

Say we did add the GameResultType->GamePlayer then in our code called that relationship:

myGamePlayed.GamesPlayed.Count

The above would load all the games played for the given type. Not a problem when your application is young and you only have a couple of games played. What happens when you have hundred or thousands of games played? Then it becomes a problem.

When we do need to filter by the game results, such as who won, we would write it from the perspective of the player. For example:

var wins = _context.Players
  .Where(p =&gt; p.Id == 1)
  .Select(p =&gt; new
  {
    PlayerName = p.Name,
    Wins = p.GamesPlayers.Where(gp => gp.GameResultType.KeyCode == 10).Count(),
  })
  .First();

With that out of the way, let us get back to coding and add the new model to the context:

public DbSet<GamePlayer> GamePlayers { get; set; }

Now that the models are setup we can create the migration:

dotnet ef migrations add CreateGamePlayersTable

Check the migration file to make sure it looks reasonable:

Now that the migration exists and looks correct we can run the migration on the database. Once the migration is complete you should be view the new GamePlayers table in the database.

dotnet ef database update

Good work. That was our most complicated table yet. This seems like a good time to stop and take a break. In the next post we will create the Game Players CRUD methods.

If you got stuck you can find completed Part 7 here.  If you have any questions or spot an issue in the code I would prefer if you opened a issue in GitHub but you can e-mail (chris.cumming@saturdaymp.com) me as well.

Posted in Code Examples, Introduction to ORMs for DBAs, Software Development | Tagged , , , , , , | Comments Off on Introduction to ORMs for DBAs: Part 7 – Create GamePlayers Table

My Takeaway from Moneyball

Moneyball cover.

Book: Moneyball: The Art Of Winning An Unfair Game
Author: Michael Lewis

Both the movie and book are great and truth be told I watched the movie well before reading the book. In both cases they do a great job of showing how statics can find undervalued baseball players. Lots of time spent focusing on what stats actually win baseball games such as the famous “he gets on base” quote.

However, that was not my takeaway from reading this book. I already know I should take actions that, statistically speaking, maximize my chances of a positive outcome. The problem is that is easier said then done. Statics only work if you are consistent over time and emotions are not consistent.

So my takeaway from Moneyball is more a reminder. Don’t let emotions derail my long term plans. Stick with actions that, statically speaking, that are likely to lead to positive outcomes and minimize negative outcomes. Don’t let one negative outcome derail my long term plan. Play the long game.

Posted in Takeaways | Tagged , | Comments Off on My Takeaway from Moneyball

Today I Learned How to Create a React-Rails App

A working example can be found here in the Saturday MP Examples GitHub.

First thing you need to do is create a basic Rails app as outlined in my previous post.  My setup is the same as creating Rails app: Ubuntu 18.04 LTS host using Docker to containerize my development environment.

Once your basic Rails app is up and running you can add React.  This example uses React-Rails.  First, you need to update the Docker file to install Node JS and Yarn.  Open up the DockerFile and change it so it looks like the below.

FROM ruby:2.5.3

# To install a later version of Node JS and Yarn.
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
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 the needed software.
RUN apt-get update -qq &amp;amp;&amp;amp; apt-get install -y build-essential libpq-dev nodejs yarn

# Create the website folder and map the Gemfiles.
RUN mkdir /website
WORKDIR /website
COPY Gemfile /website/Gemfile
COPY Gemfile.lock /website/Gemfile.lock

# Update the bundler then install the gems.
RUN gem install bundler
RUN bundle install

# Copy our files to the website.
COPY . /website
Changes to Docker file.

Actually only the top of the file is changed, the bottom is the same just with better layout and comments.  The top we add a reference to the Node and Yarn repositories then added nodejs and yarn to the install list.

Next add the required Gems: webpacker and react-rails:

# React
gem 'webpacker'
gem 'react-rails'

Now that the Docker and Gemfile is updated we can rebuild the container:

docker-compose build web
Rebuilding the Docker container with Node and Yarn.

A couple final steps.  Run the newly build container and run the following commands:

docker-compose run web bash

rails webpacker:install
rails webpacker:install:react
rails g react:install
Installing Webpacker.
Installing Webpacker React.
Generating react.

The Rails app should be React ready.  To smoke test we need a view and controller.  If you already have a page in your app you can skip this step.

Generate the home controller by executing the following:

rails g controller Home index

Generate home controller and view.

Then generate a basic React component:

rails g react:component HelloWorld greeting:string
Generate React Hello World component.

Then add the following line to the application layout file:

<%= javascript_pack_tag 'application' %>
Add React application to layout.

Finally add the following line to the home view:

<%= react_component("HelloWorld", { greeting: "Hello from react-rails." }) %>
Add React component to Home page.

Now run the add and navigate to the http://localhost:3000/home/index and you should see the React message:

Greetings from React message.
In

In memory of Walk of the Earth’s Beard Guy I present one my favourite songs Walk of the Earth songs:

You gotta hold on to what you got, babe
It ain’t always greener on the other side, you know
We ain’t rich but we’re worth a lot, babe
I wanna see the world with your hand in mine, you know

Posted in Code Examples, Software Development, Today I Learned | Tagged , | Comments Off on Today I Learned How to Create a React-Rails App