2

I have a Ruby script in a subdirectory of a Ruby on Rails application that runs in the background and performs some support tasks. In this script, would like have access to the Rails environment and the value of an application controller constant.

The best approach to retrieve these values I could find so far is based in Rails runner. If I run

cd .. && Rails runner "puts [Rails.env, ApplicationController::CONSTANT_NAME]"

from the subdirectory in shell, I get the desired values. But when I try to use the same command in my script, I get an undefined method error for active_storage:

/home/user/.rvm/gems/ruby-2.6.5/gems/railties-6.0.3.2/lib/rails/railtie/configuration.rb:96:in `method_missing': undefined method `active_storage' for #<Rails::Application::Configuration:0x0000563603fbdaa8> (NoMethodError)

The code in the script is

puts %x|cd .. && rails runner "puts [Rails.env, ApplicationController::CONSTANT_NAME]"|

The Rails application and the Ruby script run under the same user. I have Rails 6.0.3.2 and Ruby 2.6.5.

wojja
  • 175
  • 1
  • 11
  • FWIW, your code ran fine for me in a ruby script in ``lib`` (Rails 6). I don't see the value in loading the entire Rails environment and then discard it for a single command. Could you not just run the whole script via ``rails runner``? – rmlockerd Oct 01 '20 at 19:59
  • Thanks for the feedback. Yes, I agree that there is a certain amount of overhead and running the whole script via `Rails runner` is an option. In my case, the overhead is not too critical as I need this command just once at startup. I can confirm that the command works from lib/assets. I will try to move my script. – wojja Oct 02 '20 at 06:31
  • I found the reason for the error message. The script has its own Gemfile and contains `require "bundler/setup"`. This cleans the load path and causes the error when calling Rails runner or Rake tasks from within the script. I will revise the script to have a better integration with Rails. Thanks for the comments and the answer. – wojja Oct 05 '20 at 07:08

1 Answers1

1

What you want to do is write a Rake task instead:

# lib/tasks/foo.rake
namespace :foo do
  description "@TODO write a descripion"
  task bar: :environment do
    # your logic goes here
    puts [Rails.env, ApplicationController::CONSTANT_NAME]
  end
end

This task can be invoked via bin/rake foo:bar. bar: :environment loads the Rails environment for this task.

This is a lot less hacky/wonky then using the rails runner, and is the defacto way of writing tasks/scripts in Ruby that are meant to invoked from the command line.

max
  • 96,212
  • 14
  • 104
  • 165
  • Yes, indeed. The Rake tasks is the better and cleaner solution here. In my case, runtime is about 50 % shorter. – wojja Oct 05 '20 at 07:09
  • 1
    Btw, since Rails 5, the preferred way to run Rake tasks has been with the `rails` command, e.g. `bin/rails db:migrate` or `bin/rails foo` for a custom task: https://guides.rubyonrails.org/v5.0/command_line.html#custom-rake-tasks. – Jarno Lamberg May 18 '22 at 15:58