# RFC: have fly launch produce a lib/tasks/fly.rake

**URL:** <https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744>\
**Category:** General\
**Tags:** rails\
**Created:** [August 30, 2022, 12:52pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744 "2022-08-30T12:52:11Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [August 30, 2022, 12:52pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/1 "2022-08-30T12:52:11Z")

</div>

An all too common first time experience for Rails developers coming from other hosting providers is that they find out that their `assets:precompile` step needs to be run on the server instead of the build machine. They hop on [community.fly.io](http://community.fly.io) and are told to modify both their `Dockerfile` and `fly.toml` files. Two files that they are not familiar with. This user experience is sub-optimal.

With this change, they can instead be told go to into their `lib/tasks/fly.rake` file and move `=> 'assets:precompile'` from the `:build` step to the `:server` step.

Similarly, if they want to launch new services (sidekiq, anyone?), they can do so directly in the comfort of a language that they already are familiar with.

* * *

Here’s what the initial `fly.rake` would look like:

```ruby
# commands used to deploy a Rails application
namespace :fly do
  # BUILD step:
  # - changes to the fs make here DO get deployed
  # - NO access to secrets, volumes, databases
  # - Failures here prevent deployment
  task :build => 'assets:precompile'

  # RELEASE step:
  # - changes to the fs make here are DISCARDED
  # - access secrets, databases
  # - Failures here prevent deployment
  task :release => 'db:migrate'

  # SERVER step:
  # - changes to the fs make here are deployed
  # - access secrets, databases
  # - Failures here result in VM being stated, shutdown, and rollback
  # to last successful VM.
  task :server do
    sh 'bin/rails server'
  end
end

```

Following are the changes to the `Dockerfile` and `toml` file that make this work:

* * *

Before, in `Dockerfile`:

`RUN bundle exec rails assets:precompile`

After, in `Dockerfile`:

`RUN bin/rails fly:build`

After, in `lib/tasks/fly.rake`:

```ruby
task :build => 'assets:precompile'

```

* * *

Before, in `fly.toml`:

`release_command = "bundle exec rails db:migrate"`

After, in `fly.toml`:

`release_command = "bin/rails fly:release"`

After, in `lib/tasks/fly.rake`:

```ruby
task :release => 'db:migrate'

```

* * *

Before, in `fly.toml`:

`SERVER_COMMAND = "bundle exec puma"`

After, in `fly.toml`:

`SERVER_COMMAND = "bin/rails fly:server"`

After, in `lib/tasks/fly.rake`:

```ruby
task :server do
  sh 'bin/rails server'
end

```

Note: `bin/rails server` will run whatever web server you have in your Gemfile, and Rails generates a Gemfile including puma by default.

---

<div class="post-metadata">

**Author:** ![Brad](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/brad/32/4429_2.png) [@Brad](https://community.fly.io/u/Brad)\
**Post date:** [August 30, 2022, 10:57pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/2 "2022-08-30T22:57:36Z")

</div>

I like that this simplifies the Rails ↔ Fly integration into just one file.

As it stands, we have to tell people in our docs stuff like this:

“To change how the server boots, change the SERVER\_COMMAND in the [env] directive of the fly.toml file”

“To change the build command, look at this line in the `Dockerfile`”

In this new world, we’d tell people, “it’s all in the Rakefile!”. It’s self-evident and not surprising.

The use of a Rakefile isn’t too heavy either, so we don’t have to maintain a gem or worry about too much “magic” getting in between this interface and all the stuff Fly puts on a users system.

At first glance it did feel a little weird seeing the sever command in a Rakefile, but I quickly got over that when I ran `mix phx.server` to fire up ui-ex today.

Longer term it would be great to bake something like this into `flyctl`, but short term this feels like the best solution for smoothing things over for Rails devs. It’s very easy to throw this out when we come up with a better way.

---

<div class="post-metadata">

**Author:** ![miharekar](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/miharekar/32/14766_2.png) [@miharekar](https://community.fly.io/u/miharekar)\
**Post date:** [September 2, 2022, 2:53pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/3 "2022-09-02T14:53:47Z")

</div>

I, like many others, have been looking to migrate my Heroku apps to Fly. Issues with ENV vars at build time have been by far the most painful. Luckily the community has had these issues before so I managed to figure out what needed to be done. But because of this change, all the docs and community answers are out of sync with instructions like “remove RUN bundle exec rails assets:precompile” row. 😅

But the biggest issue is that most Rails apps require at least some secrets for asset precompilation. And you can’t have secrets without `RAILS_MASTER_KEY`. And as far as I can tell there’s no good way to expose it safely in the build step. So my current workaround is that I edited this rake file to

```auto
  task server: "assets:precompile" do
    sh "bin/rails server"
  end

```

Is there a better way? Should something like this be the default?

In a perfect world secrets would be accessible in the build step too or at least there would be a simple-ish way to do that.

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 2, 2022, 3:14pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/4 "2022-09-02T15:14:25Z")

</div>

> [@miharekar](#):
>
> But the biggest issue is that most Rails apps require at least some secrets for asset precompilation.

For some values of _most_, perhaps. 🙂

I’ll note that Rails itself is moving the other way, with things like import maps (now), and thing like [GitHub - rails/propshaft: Deliver assets for Rails](https://github.com/rails/propshaft) in the pipeline. But clearly we have to deal with the world as it is today.

As to your comments and questions:

- Indeed, the docs are out of sync. Things are moving fast, and I hope to have most of the docs cleaned up over this holiday weekend in the US. The community answers all represent the point in time at which they are given, and hopefully you agree that moving this to the rakefile is a step forward.
- Yes, the changes you made to the rake file are the recommended approach for applications that require access to secrets.
- No, this is not the default. The downside to the change you made is that in the rare cases where your precompile fails, VMs will be brought up, down, and back up again.
- As to what a perfect world would look like: that we are going to move very slowly on. Leaking secrets can lead to a lot of unhappy people. Fly provides a lot of flexibility as to where build steps can take place - including your own hardware! - and we need to work through the implications that balance flexibility without compromising safety.

So… you have got something that should work for you now (and, realistically, given how rarely `assets:precompile` fails, will not likely cause you problems). But please give us feedback on any problems you may encounter.

Welcome to fly! I hope to make things better for Rails developers like yourself.

---

<div class="post-metadata">

**Author:** ![miharekar](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/miharekar/32/14766_2.png) [@miharekar](https://community.fly.io/u/miharekar)\
**Post date:** [September 6, 2022, 5:08pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/5 "2022-09-06T17:08:34Z")

</div>

I actually take it all back, I’m very sorry! 😅 The defaults are great.

And just because someone might search this community I’ll add some more info, so they might be able to find this post.

The reason I had issues with asset precompilation is because of  
`has_one_attached :avatar, service: :cloudinary`. The method calls `validate_service_configuration` on `active_storage` and since it can’t find it, it fallbacks to the default one, in my case being AWS. There’s no AWS config either so it raises `Aws::Sigv4::Errors::MissingCredentialsError`.

I got around it quite easily by adding

```auto
ENV AWS_ACCESS_KEY_ID=1
ENV AWS_SECRET_ACCESS_KEY=1

```

in `Dockerfile` right under

```auto
ENV SECRET_KEY_BASE 1

```

I don’t really need AWS for building assets so this now works perfectly.

Thanks again!

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 6, 2022, 7:54pm UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/6 "2022-09-06T19:54:57Z")

</div>

> [@miharekar](#):
>
> ```auto
> ENV AWS_ACCESS_KEY_ID=1
> ENV AWS_SECRET_ACCESS_KEY=1
> 
> ```

I’ve adjusted the Dockerfile produced as follows:

```auto
# The following enable assets to precompile on the build server. Adjust
# as necessary. If no combination works for you, see:
# https://fly.io/docs/rails/getting-started/existing/#access-to-environment-variables-at-build-time
ENV SECRET_KEY_BASE 1
# ENV AWS_ACCESS_KEY_ID=1
# ENV AWS_SECRET_ACCESS_KEY=1

```

This will make a release of flyctl in the near future. Once it lands, I’ll update the documentation to suggest uncommenting out these lines if AWS is used by the config.

Thanks for following up!

---

<div class="post-metadata">

**Author:** ![miharekar](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/miharekar/32/14766_2.png) [@miharekar](https://community.fly.io/u/miharekar)\
**Post date:** [September 7, 2022, 5:45am UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/7 "2022-09-07T05:45:15Z")

</div>

Awesome, thanks!

Not really related but another possible improvement to this auto generated files would be to detect package.json or yarn.lock or something and if none are detected, not include the `node` stuff in the Dockerfile and fly.toml. My rails 7 app, for example, works with importmaps so I don’t have any of this JS crap in the repo and no need for node 😅

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [September 7, 2022, 10:14am UTC](https://community.fly.io/t/rfc-have-fly-launch-produce-a-lib-tasks-fly-rake/6744/8 "2022-09-07T10:14:38Z")

</div>

Already on my todo list! My [book](https://pragprog.com/titles/rails7/agile-web-development-with-rails-7/) avoids the use of node, as do my personal apps - [example](https://github.com/rubys/showcase#readme).
