LoginSignup
0
2

More than 5 years have passed since last update.

HPなどでユーザーが行うアクションを非同期処理でかっこよく眠らせる

Last updated at Posted at 2019-01-18

こんにちは
railsでインターンをしているものです。
今回はhpに関する依頼があったので実装していきます。

依頼

お問い合わせフォーム

  • ユーザーがボタンを連打すると何重にもメールが届くのでそれを阻止してほしい
  • 非同期処理を行なって、メール送信の動作を裏で行いユーザーには完了のページをすぐに移行できるようにする

一つずつ見ていきましょう

ボタン連打を防ぐ

人ってうまくいかないと何回も試行錯誤しますよね?
お問い合わせフォームも然りです。
メールの送信に時間がかかるとその場面でページが止まってしまいます。
これは、プログラムが順番に処理を行うのでメール送信が完了するまで次のページに移行としないんです。(うまい)
後でもう少し詳しくやりますが、このせいでユーザーは送信できているか不安になり、何度もボタンを連打していきます。
AP2018FTHG5353_TP_V4.jpg

PAKUTASO からの引用

そこで必要になるのが二重投稿防止の処理
しかし何とJSでちょこちょこっと描いてあげるだけでできるのです。
参考
以下を追加し

/app/assets/javascripts/confirm.js
$(function () {

  $("form").submit(function () {
    var self = this;
    $(":submit", self).prop("disabled", true);
    setTimeout(function () { //一定時間でボタンをenabledにするようにした方が親切らしい。
      $(":submit", self).prop("disabled", false); 
    }, 10000);
  });

});

こちらを記述
これでボタンが一定時間立たないと押せなくなりました。

ちなみにsubmit自体にdisableを記述する方法などもありましたが、複数のsubmitがある際に適用できる場合を考えこちらを採用しました。

非同期処理でメール送信の動作を裏で行う

先ほど記述した通り、プログラムには順番があり、それが完了しないと次の処理には移りません。
これを同期処理と呼びます。

本来ならばそれが普通なのですが、メール送信や画像投稿など時間のかかる処理をする際にはユーザーが待たなくてはなりません。
もう連打はできないはずなのでこれではユーザーが何もすることができませんね。

そこで、非同期処理を行なってメール送信の処理を裏に回して次の処理を先に行えるようにします。
非同期処理をもっと理解したい人はこちら


まずはrailsで非同期処理のリサーチ
Railsでは非同期処理を実装するのに便利なgemがいくつかあり、有名どころだと、

  • sidekiq
  • rescue
  • delayed job

が挙げられていました。
ですが、僕は一目でどれにするか決めました。

sidekiq(恐らくsidekick(相棒))、君こそが僕のパートナーだ!!

素晴らしいネーミングセンスに一目惚れしました。こんなことってあるんですね。


あとはここここ,ここら辺を参考に実装していきます。

いざ、実食

sidekiqにはredisがバックグラウンド(ジョブ管理)に必要なのでbrewでインストール

brew install redis

続いてsidekiqのgem登録

Gemfile
gem 'sidekiq'
bundle install

続いて、config/sidekiq.ymlに以下を記述

/config/sidekiq.yml
:concurrency: 25
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
  - default

Active Jobがsidekiqを使う設定

/config/application.rb
config.active_job.queue_adapter = :sidekiq

Jobの作成

bundle exec rails g job My

MyJobクラスの実装

/jobs/my_job.rb
class MyJob < ActiveJob::Base
  queue_as :default

  def perform(@contact)
    # 非同期で実行させたい処理を書く(今回はメール送信)
    Mailer.post_email(@contact).deliver
  end
end

ContactMailerクラスの実装

/models/mailer.rb
class Mailer < ApplicationMailer
  def post_email(contacts)
    @contacts = contacts
    mail to: 'info@hoge.com',
         bcc: 'hoge@hoge.com',
         subject: "[HP]お問い合わせ"
  end
end

コントローラー作成

rails generate controller contact

メールを送信するアクション実装

/app/controllers/mailer.rb
class ContactController < ApplicationController
  def run
    @contact = Contact.new(contact_params) #contactクラスの実装は割愛します

    # 即時実行する場合
    MyJob.perform_later(@contact)
    # 時間を置いて実行する場合
    MyJob.set(wait: 5.second).perform_later(@contact) #5秒後実行
    MyJob.set(wait: 10.second).perform_later(@contact) #10秒後実行

    render :nothing => true
  end
end

ルーティング

/config/routes.rb
post 'contact/run'

お疲れ様です。ここまでで一旦実装は完了です。


続いて
redisの起動

redis-server

Screenshot 2019-01-18 at 11.45.42.png
別のターミナルにて、sidekiqを起動

bundle exec sidekiq

Screenshot 2019-01-18 at 11.45.52.png
かっこいい

また別のターミナルにて、Railsを起動

bundle exec rails s

ログを監視

tail -f log/development.log

ジョブを実行

curl http://localhost:3000/start/run -X POST -d ''

お疲れ様でした。
これでかっこよくユーザーの行動を眠らせることができましたね!!

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2