[WithPopup] submitと同時にポップアップを開くRails用Gem


Webアプリケーションを作っていて、何らかのアクションの後にポップアップを開きたい場面があると思います。例えば『とあるデータを登録して、登録が完了した後にポップアップでプリント画面を開きたい』場合とか。

普通に考えると、登録後に遷移する画面内のJavascriptでwindow.openすれば良さそうですが、これはブラウザのポップアップブロック機能に引っ掛かります。ポップアップを許可してあげれば問題ないのですが、不特定多数に使ってもらうWebサービス等の場合は、なるべくならセキュリティ警告をユーザーに見せたくはありません。

そんなときの常套手段のひとつとして、

  1. 登録ボタンクリック時に、あらかじめポップアップを開いておき
  2. 登録完了後にさっき開いたポップアップをリロードする

という手が用いられます。1はポップアップブロックに引っ掛かりません。clickのように、『ユーザーが意図的に起こすアクション』内にはポップアップを開く処理を書いても大丈夫なのです。

これを実現する具体的なコードのイメージは次のような感じになります。

📄登録画面.js
$('.submit').on('click', function(e) {
  window.open('', 'popup');
});
📄登録完了後の画面.js
var popup = window.open('', 'popup');
popup.location.href = '/print';

登録時にバリデーションエラーがあった場合は、開いてしまったポップアップを閉じてやります。

📄登録画面.js
var popup = window.open('', 'popup');
popup.close();

流れとしては↓こんな感じ↓になります。

Demo
Demo

先にポップアップが開いてしまうのは少々格好悪いですが、一応目的は達成できました。WithPopupはこれと同じことをやってくれるrails用のgemです。

WithPopup

まずはインストールの仕方から。Gemfileに次のコードを追加します。

📄Gemfile
gem 'with_popup'

bundler使ってない人はgem install with_popupしてください。

次にapp/assets/javascripts/application.jsを編集して、with_popupをjqueryより後に記述します。

📄application.js
//= require jquery
//= require jquery_ujs
//= require with_popup
//= require_tree .

使い方

クリックを伴うようなDOMを生成するForm用のヘルパー(link_toとかsubmit_tagとか)をラップしています。前段の登録後にプリント画面を開く例をコードにすると、次のような感じになります。

📄登録画面.html.erb
<%= form_for @post do |f| %>
  ...
  # Submit while opening a popup window
  <%= f.submit_with_popup %>
<% end %>

f.submit_with_popupという箇所が通常とは違うところ。これはf.submitと書くのと同じ(透過的に委譲している)で、submiと同時にポップアップを開いてくれます。

開いたポップアップの命運はコントローラが決めます。

📄登録アクション.rb
def create
  @post = Post.new(params[:post].permit(...))
  if @post.save
    # Show print preview in the popup window you've opened
    reload_popup print_post_path(@post)
    redirect_to @post
  else
    # Close the popup window
    close_popup
    render :new
  end
end

基本的な使い方はこれだけです。Javascriptは一切書く必要はありません。簡単でしょ?

その他詳細はgithub上に記載しています。かなりニッチなニーズしかないと思いますが、何かの役に立てばと幸いです。

リンク

関連する記事


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください