🦈

GoogleフォームをRailsでカスタマイズする

に公開

作成したGoogleフォームを画面内に埋め込むだけではデザインに統一性が出ないので、erb形式で入力フォームを作って送信させてみました。

完成形

作り方

1. まずは普通にGoogleフォームを作る

  • 設定の項目では、今回煩雑さを避けるため回答を「収集しない」にして、その他の設定も全てオフにしています。
  • 作り終わったら、公開状態にして回答者へのリンクを開いてください。
    • ただし、「URLを短縮」はしないでください。(後のURI作成に響きます。)
    • プレビューのリンクと回答者へのリンクは見た目同じでもURI全然違いますので注意してください。(わしゃここでつまずいた。)

2. Googleフォームの回答ページから必要な値を取り出す

必要なものは主に2種類です。

  • フォーム送信先のURI
  • 各回答項目を入れるためのnameの値

探し方にはコツがあります。

  • 回答者用のページを開いたら、まずは全項目適当に何か入力してください。
  • 次に、検証ページを開いて<formで検索にかけてください。
    • <form action="https://docs.google.com/forms/...という記述からURLだけメモに控えておいてください。
  • 次に、entry.で検索にかけてください。
    • 先ほど適当に入力した値(value)の隣にある、nameの値をメモに控えておいてください。
    • ちなみに適当に入力しておかないと、entry.と打ってもhidden状態で見つからないのでご注意を。

3. ビューで入力フォームを作る

form_withを使って入力フォームを作ります。(tailwindCSS使ってます。)

app/views/footers/contact_form.html.erb

<div class="relative top-24 flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
  <div class="sm:mx-auto sm:w-full sm:max-w-sm">
    <h2 class="mt-10 text-center text-2xl/9 font-bold">お問い合わせ</h2>
  </div>

  <%= form_with url: "/footers/contact_form", method: :post, local: true, data: { turbo: false } do |f| %>
    <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
      <!-- お名前 -->
      <div>
        <%= f.label :name, "お名前", class: "block text-sm/6 font-medium" %>
        <div class="mt-2">
          <%= text_field_tag :name, nil, required: true, placeholder: "ポル太郎", class: "block w-full rounded-md bg-primary px-3 py-1.5 text-base outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm" %>
        </div>
      </div>

      <!-- メールアドレス -->
      <div class="mt-4">
        <%= f.label :email, "メールアドレス", class: "block text-sm/6 font-medium" %>
        <div class="mt-2">
          <%= email_field_tag :email, nil, required: true, placeholder: "mail@example.com", class: "block w-full rounded-md bg-primary px-3 py-1.5 text-base outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm" %>
        </div>
      </div>

      <!-- お問い合わせ内容 -->
      <div class="mt-4">
        <%= f.label :content, "お問い合わせ内容", class: "block text-sm/6 font-medium" %>
        <div class="mt-2">
          <%= text_area_tag :content, nil, required: true, rows: 4, placeholder: "ご質問やご要望などをご記入ください", class: "block w-full rounded-md bg-primary px-3 py-1.5 text-base outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm" %>
        </div>
      </div>

      <!-- 送信ボタン -->
      <div class="mt-8">
        <%= f.submit "送信", class: "actions  flex w-full justify-center rounded-md bg-accent px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"%>
      </div>
    </div>
  <% end %>
</div>
  • 「ラジオボタンとかのときはどうせぇっちゅうねん」という方は、こちらの記事が大変参考になりましたので共有させていただきます。この記事の末にも改めて参考記事まとめておきますね。

  • text_field_tag :name : キーの名前はなんでも大丈夫です。

  • キーの後ろのnil : これ入れとかないと入力欄がどえらいことになりました。まなびですね〜。

4. コントローラーでフォームの表示と送信を設定する

コントローラーでは主に以下のアクションを作ります。

  • ビューファイルを表示させるアクション
  • ビューから送信された内容をGoogleフォームに送るアクション

app/controllers/footers_controller.rb

require 'net/http'
require 'uri'

class FootersController < ApplicationController
  def contact_form
  end
  def create
    uri = URI.parse("https://docs.google.com/forms/d/e/1FAIpQLSfOQy2m7AFpztirJzxPL0l-GUE5Q6FjohAyRZGfq42TCOB3Rw/formResponse")

    # Googleフォームの各エントリIDに合わせてフォーム値をセット
    form_data = {
      "entry.2002479067" => params[:name], # お名前
      "entry.2121994439" => params[:email], # メールアドレス
      "entry.149706489"  => params[:content] # お問合せ内容
    }

    Net::HTTP.post_form(uri, form_data)

    flash[:notice] = "お問い合わせいただきありがとうございます"
    redirect_to root_path
  end

# 中略
end
  • require ‘net/http’
    • Ruby公式参照
    • 汎用データ転送プロトコルHTTPを扱うライブラリ。
    • フォームの情報を送信するのに使います。
  • require ‘uri’
    • Ruby公式参照
    • URI を扱うためのモジュールで、URI.parseのメソッドが使えるようになります。
    • 文字列からURIの中身を理解します。
      • httpとか、host名とか、ポート番号とか、パスとか。
  • *URI*.parse
    • form actionから手に入れたURIの文字列をURIオブジェクトとして解釈させます。
  • form_data
    • viewから送られてきたform_withの値を、Googleフォーム name属性に入れ込みます。
  • Net::HTTP.post_form(uri, form_data)
    • GoogleフォームのURIに値を送信します。

先ほどメモした内容を入れ込む

  • URI.parseの部分にフォーム送信先のURIを入れてください。
  • params[:name]にはビューで指定したキーを、"entry.2002479067"部分にはnameの値をentry.付きで指定してください。

5. ルーティング

config/routes.rb

  # おといあわせ
  get "/footers/contact_form", to: "footers#contact_form"
  post "/footers/contact_form", to: "footers#create"

この状態で、実際にフォームが送信できるか試してみてください。
うまくいくことを祈ります!

おまけ

Googleフォームの「メールアドレスを収集する」を使いたい場合

  • フォームの設定画面で、回答「メールアドレスを収集する」を「回答者からの入力」とします。
  • controller側のキーの部分をemailAddressにしてください。
    "emailAddress" => params[:email]
    これだけでOKです。

複数選択可能なチェックボックス(チェック必須)を使いたい場合

  • 単体の入力欄なら、required: trueを入れておけばHTML側が「入力し忘れてんで」と言ってくれるんですけど、チェックボックスの場合は対応してくれないようです。なので、ある程度カスタマイズしないといけません。
  • ここではモデルを作らず、コントローラーでバリデーションみたいなことをさせる方法を取り入れました。
  • 一応、最も手っ取り早いのでjQuery-Validation-EngineというjQueryがバリデーション判断してくれるライブラリがあるんですけど、わざわざこれのために入れるのも・・・というのと、最終更新が2019年なので使用が躊躇われました。
  • モデルファイルを作ってバリデーションの機能を持たせることも考えましたが、やはりこの機能のために新しく作るのもなぁ。――という方向けの方法となっています。

複数選択ありのチェックボックスタイプで値を送信します。ただし、1つでもチェックを入れなければならない制限を設けます。

app/views/footers/contact_form.html.erb

      <!-- お問い合わせの種類 -->
      <div class="mt-4">
        <%= f.label :kind_of_contact, "お問い合わせの種類", class: "block" %>
        <div class="mt-2 space-y-2">
          <!-- 選択肢を配列で表示 -->
          <% kinds = [
            "バグ・エラーなど不具合に関する報告",
            "感想",
            "改善要請",
            "アプリに関する問い合わせ",
            "その他"
          ] %>

          <!-- 配列を順番に処理 -->
          <% kinds.each_with_index do |kind, index| %>
            <div class="flex items-center space-x-2">
              <%= check_box_tag 'kind_of_contact[]', kind, params[:kind_of_contact].presence || false, id: "kind_of_contact_#{index}",  class: "form-checkbox h-4 w-4 text-indigo-600 border-gray-300 rounded" %>
              <%= label_tag "kind_of_contact_#{index}", kind, class: "text-sm text-gray-700" %>
            </div>
          <% end %>
        </div>
      </div>
  • 配列に選択した選択肢(値)を入れて送っているイメージ。
  • params[:kind_of_contact].presence || falseについては後述します。
  • idがあることで「どれがどの選択肢?」を判断できるようになってます。

app/controllers/footers_controller.rb

  def contact_form
  end
  def create
    # 送信先の文字列をURIオブジェクトに変換
    if params[:kind_of_contact].blank?
      flash[:alert] = "お問い合わせの種類を1つ以上選択してください"
      render :contact_form and return
    end
    uri = URI.parse("https://docs.google.com/forms/d/e/1FAIpQLSfOQy2m7AFpztirJzxPL0l-GUE5Q6FjohAyRZGfq42TCOB3Rw/formResponse")

    form_data = { "entry.149706489"  => params[:content] } # お問合せ内容

    Net::HTTP.post_form(uri, form_data)

    flash[:notice] = "お問い合わせいただきありがとうございます"
    redirect_to root_path
  end
  • form_dataの書き方は他と同じです。
  • createアクション冒頭にバリデーション的な機能を設けました。
  • ただし、モデルを作らずtext_field_tagみたいなhoge_tagを使う場合は、renderしても入力した値を再表示してくれないんですよね。(せっかく書いた他の部分も真っ白に!)
  • なので、本記事の中でnilについて書いてあった場所を全てparams[:キー].presence || nilという風に書くことで、「デフォルトはnilだけど、もしなんちゃってバリデーションに引っ掛かったら、送ろうとしていた値を読み込んで再表示させる」ようにしました。
          <!-- お名前 -->
        <div>
          <%= f.label :name, "お名前", class: "block text-sm/6 font-medium" %>
          <div class="mt-2">
            <%= text_field_tag :name, params[:name].presence || nil, required: true, placeholder: "ポル太郎", class: "block w-full rounded-md bg-primary px-3 py-1.5 text-base outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm" %>
          </div>
        </div>
    

参考リンク

Discussion