[Ruby] [Rails] Implementation of coupon function (with automatic deletion function using batch processing)

2 minute read

Target

![ezgif.com-video-to-gif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/579893/bfdf64fb-3ea0-732c-(9bd1-2a4de401f84d.gif)

Development environment

・Ruby: 2.5.7 Rails: 5.2.4 ・Vagrant: 2.2.7 ・VirtualBox: 6.1 ・OS: macOS Catalina

Premise

Implemented below.

Slim introductionBootstrap3 installedImplementation of login functionPosting function implementation

Implementation

1. Add a column

terminal


$ rails g model Coupon user_id:integer is_valid:boolean limit:integer
class CreateCoupons <ActiveRecord::Migration[5.2]
  def change
    create_table :coupons do |t|
      t.integer :user_id
      t.boolean :is_valid, default: true # Add "default: true"
      t.integer :limit

      t.timestamps
    end
  end
end

terminal


$ rails db:migrate

2. Edit the model

user.rb


# Addition
has_many :coupons, dependent: :destroy

coupon.rb


class Coupon <ApplicationRecord
  belongs_to :user

  enum is_valid: {'valid': true,'invalid': false}

  def self.coupon_create(user)
    coupon = Coupon.new(user_id: user.id, limit: 1)
    coupon.save
  end

  def self.coupon_destroy
    time = Time.now
    coupons = Coupon.all
    coupons.each do |coupon|
      if coupon.created_at + coupon.limit.days <time && coupon.is_valid =='valid'
        coupon.is_valid ='Invalid'
        coupon.save
      end
    end
  end
end

[Explanation]

① Manage coupon status with enum.

enum is_valid: {'valid': true,'invalid': false}

② Define the method to create a coupon.

def self.coupon_create(user)
  coupon = Coupon.new(user_id: user.id, limit: 1)
  coupon.save
end

③ Define the method to delete the coupon.

def self.coupon_destroy
  time = Time.now
  coupons = Coupon.all
  coupons.each do |coupon|
    if coupon.created_at + coupon.limit.days <time && coupon.is_valid =='valid'
      coupon.is_valid ='Invalid'
      coupon.save
    end
  end
end

** ◎ If 24 hours have passed since the coupon was created and the coupon status is valid, change it to invalid and save. **

if coupon.created_at + coupon.limit.minutes <time && coupon.is_valid =='valid'
  coupon.is_valid ='Invalid'
  coupon.save
end

3. Create/edit coupons_controller.rb

terminal


$ rails g controller coupons index

coupons_controller.rb


class CouponsController <ApplicationController
  def index
    @coupons = Coupon.where(user_id: current_user.id, is_valid:'valid')
  end
end

4. Edit books_controller.rb

This time, we will implement to issue a coupon if the book is posted successfully.

books_controller.rb


def create
  @book = Book.new(book_params)
  @book.user_id = current_user.id
  if @book.save
    Coupon.coupon_create(current_user) # Added
    redirect_to books_path
  else
    @books = Book.all
    render'index'
  end
end

5. Change date and time settings

① Edit application.rb.

application.rb


module Bookers2Debug
  class Application <Rails::Application
    config.load_defaults 5.2
    config.time_zone ='Tokyo' # Added
  end
end

(2) Create/edit a file that sets the date and time format

terminal


$ touch config/initializers/time_formats.rb

time_formats.rb


Time::DATE_FORMATS[:datetime_jp] ='%Y/%m/%d/%H:%M'

6. Edit View

slim:coupons/index.html.slim


.row
  .col-xs-3

  .col-xs-6
    table.table
      thead
        tr
          th
            | Coupon number
          th
            | Title

      tbody
        [email protected]_index(1) do |coupon, index|
          tr
            td
              = index
            td
              -limit = coupon.created_at + coupon.limit.minutes
              = limit.to_s(:datetime_jp)

  .col-xs-3

[Explanation]

① Display one day after the coupon creation date and time in the format set in 5.

- limit = coupon.created_at + coupon.limit.minutes
= limit.to_s(:datetime_jp)

7. Implementation of automatic deletion function

① Gem introduced

Gemfile


# Addition
gem'whenever', require: false

terminal


$ bundle

② Create/edit "schedule.rb"

terminal


$ bundle exec wheneverize.

config/schedule.rb


env :PATH, ENV['PATH'] # Specify relative path from absolute path
set :output,'log/cron.log' # Set output file for log
set :environment, :development # set environment

every 1.minute do
  runner'Coupon.coupon_destroy'
end

Reflect ###4.cron

terminal


$ bundle exec whenever --update-crontab

Commands frequently used in batch processing

crontab -e ➡︎ Edit cron on the terminal

$ bundle exec whenever ➡︎ Check cron settings

$ bundle exec whenever --update-crontab ➡︎ Reflect cron

$ bundle exec whenever --clear-crontab ➡︎ Remove cron