[RUBY] Rails: How to write a rake task nicely

Good feeling = the following two points

  1. Easy to test
  1. (To some extent) the writing style can be unified among engineers

etc

code

lib/tasks/issue_6885.rake


require_relative 'helpers/all_user_name_update_helper.rb'

namespace :issue_6885 do

  desc 'This is a sample'
  task all_user_name_update: :environment do
    helper = AllUserNameUpdateHelper.new

    helper.main
  end
end

lib/tasks/helpers/all_user_name_update_helper.rb


require_relative 'rake_helper_template'

class AllUserNameUpdateHelper < RakeHelperTemplate
  NEW_NAME = 'bar'

  def main
    template do |logger|
      all_users = get_all_user
      logger.info("Number of target users: #{all_users.size}")

      if all_users.blank?
        logger.info('The process ends because the number of target users was 0.')
        return
      end

      all_users.each { |user| update_name(user, NEW_NAME) }
    end
  end

  private

  def get_all_user
    User.all
  end

  def update_name(user, new_name)
    user.update!(name: new_name)
    user
  end
end

lib/tasks/helpers/rake_helper_template.rb


class RakeHelperTemplate
  #Also performs standard output
  def make_logger(log_file_path)
    logger = ActiveSupport::Logger.new(log_file_path)
    stdout_logger = ActiveSupport::Logger.new(STDOUT)
    broadcast_logger = ActiveSupport::Logger.broadcast(stdout_logger)
    logger.extend(broadcast_logger)
    logger.formatter = Logger::Formatter.new
    logger
  end

  #Make the log file name the same as the task name (replace it because it is better not to use a colon)
  #Cases called from other than the execution of the rake task (eg:spec) should be taken into consideration
  def make_log_file_path
    task_name = Rake.try(:application)&.top_level_tasks&.[](0)&.gsub(':','_') || Rails.env
    log_file_name = "#{task_name}.log"
    Rails.root.join('log', log_file_name)
  end

  def template
    log_file_path = make_log_file_path

    #Be sure to dryrun unless you explicitly pass the string false
    is_dryrun = ENV['is_dryrun'] != 'false'

    logger = make_logger(log_file_path)
    logger.info("Start. is_dryrun: #{is_dryrun}")

    ActiveRecord::Base.transaction do
      yield(logger)
      raise ActiveRecord::Rollback if is_dryrun
    end

    logger.info("Finish. log_file_path: #{log_file_path}")
  end
end

Execution example

When making a dry run


$ is_dryrun=false bundle exec rake issue_6885:all_user_name_update
I, [2020-09-27T13:33:27.229764 #13040]  INFO -- : Start. is_dryrun: true
I, [2020-09-27T13:33:27.556890 #13040]  INFO -- :Number of target users: 1
I, [2020-09-27T13:33:27.755933 #13040]  INFO -- : Finish. log_file_path: /app/log/issue_6885_all_user_name_update.log 

point

  1. The .rake file only calls the helper class, rake's DSL? I tried to test the method of the class that I am accustomed to writing without worrying about the way of doing things
  1. Use yield to standardize dryrun and logger (part of) so that you don't have to define them every time you create a rake task.

Once you have a template, you can concentrate on what you want to do like all_user_name_update_helper.rb! (^ ○ ^)

Impressions

Recommended Posts

Rails: How to write a rake task nicely
How to write Rails
[Rails] How to write when making a subquery
How to write Rails validation
How to write Rails seed
How to write Rails routing
How to write a date comparison search in Rails
[Rails] How to write in Japanese
How to write a ternary operator
Rails on Tiles (how to write)
[Rails] How to write exception handling?
How to write a migration from Rails datetime type to date type
[Basic] How to write a Dockerfile Self-learning ②
How to insert a video in Rails
[Introduction to Java] How to write a Java program
[rails] How to create a partial template
[SpringBoot] How to write a controller test
[Reading impression] "How to learn Rails, how to write a book, and how to teach"
[Rails] How to create a graph using lazy_high_charts
How to run a djUnit task in Ant
How to write dockerfile
How to uninstall Rails
How to write docker-compose
How to write Mockito
How to implement a like feature in Rails
How to easily create a pull-down in Rails
[Rails] How to create a Twitter share button
How to write migrationfile
How to make a follow function in Rails
[Rails] Implement rake task
[Rails] How to create a signed URL for CloudFront
How to implement a like feature in Ajax in Rails
[Ruby on Rails] How to write enum in Japanese
How to write a unit test for Spring Boot 2
How to delete a new_record object built with Rails
java: How to write a generic type list [Note]
How to manually generate a JWT with Rails Knock
[How to insert a video in haml with Rails]
[Rails 6] How to set a background image in Rails [CSS]
[Rails] How to load JavaScript in a specific view
How to write a core mod in Minecraft Forge 1.15.2
How to get started with creating a Rails app
[Rails] How to install a decorator using gem draper
[rails] How to post images
How to write good code
[Rails] How to use enum
Bit Tetris (how to write)
[Rails] How to install devise
[Rails] How to use enum
How to write java comments
How to leave a comment
How to read rails routes
Let's define a Rake task.
[Refactoring] How to write routing
Great poor (how to write)
[Note] How to write Dockerfile/docker-compose.yml
How to use rails join
How to write Junit 5 organized
How to terminate rails server
[Rails] How to use validation
To write a user-oriented program (1)