Featured image of post Running Ruby on Rails web apps with .NET Aspire

Running Ruby on Rails web apps with .NET Aspire

Learn how to extend the .NET Aspire app model for Ruby on Rails web apps with insights on setup, custom resource creation, and networking tips.

The Microsoft ecosystem is not kind to Ruby developers. The Ruby SDK for Azure was retired in February 2021, and the support for Ruby in the OpenAPI client generator Kiota is extremely limited, if not unusable. However, .NET Aspire is a special case. This ambitious local development orchestrator is not tied to any specific technology, as I explained in my previous article on the inner workings of .NET Aspire. Therefore, it is possible to run Ruby on Rails web applications on it.

Please note, the source code presented in this article is subject to change, as .NET Aspire is still under development.

Update 4/11/2024: This post has been updated to reflect the latest changes in .NET Aspire preview 5.

# Prerequisites

# Developing a custom Rails resource for .NET Aspire’s app model

.NET Aspire uses an “application model”, which represents the list of resources that make up a distributed application. The two primary resource types in .NET Aspire are executables and containers. For Ruby on Rails web applications, we want to create an executable with the following command:

ruby bin/rails server

This command is used to start a Rails application and is cross-platform. Thanks to the extensibility of the .NET Aspire app model, we can define our own Rails resource, which inherits from the ExecutableResource class in .NET Aspire. Here is the complete source code for declaring a Rails application in .NET Aspire:

using Microsoft.Extensions.Hosting;

namespace Aspire.Hosting;

internal class RailsAppResource(string name, string workingDirectory)
    : ExecutableResource(name, "ruby", workingDirectory);

internal static class RailsAppExtensions
{
    public static IResourceBuilder<RailsAppResource> AddRailsApp(
        this IDistributedApplicationBuilder builder, string name, string command, string workingDirectory, string[]? args = null)
    {
        var resource = new RailsAppResource(name, workingDirectory);

        return builder.AddResource(resource)
            .WithArgs(context =>
            {
                context.Args.Add("bin/rails");
                context.Args.Add(command);

                if (args is not null)
                {
                    foreach (var arg in args)
                    {
                        context.Args.Add(arg);
                    }
                }
            })
            .WithOtlpExporter()
            .WithEnvironment("RAILS_ENV", builder.Environment.IsDevelopment() ? "development" : "production")
            .ExcludeFromManifest();
    }
}

Let’s focus on the experience of declaring a Rails application in your Program.cs file of your .NET Aspire project:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddRailsApp("myrailsapp", "server", "path/to/your/rails/app")
    .WithEndpoint(port: 3000, scheme: "http", env: "PORT");

builder.Build().Run();

# .NET Aspire preview 5 changes

  • You can now disable the Aspire proxy for a Rails app resource by specifying isProxied as false: .WithEndpoint(port: 3000, scheme: "http", env: "PORT", isProxied: false).
  • If your Rails app is using an unsecured transport (non-TLS http) protocol, you need to set the environment variable ASPIRE_ALLOW_UNSECURED_TRANSPORT to true. See Allow unsecure transport in .NET Aspire.

# References