akishin999の日記

調べた事などを書いて行きます。

Rails 2.2.2 の submit_tag で disable_with と confirm を同時に指定すると confirm が効かない

Rails の submit_tag には submit ボタンクリック時にボタンを disable にして二重送信を防止する disable_with オプションがあります。

<%= submit_tag '送信', :disable_with => '送信中です...' %>


ところが、Rails 2.2.2 では生成される JavaScript の不具合で、IE では上手く動作してくれません(確認したのは VistaIE7 です)。


この問題については、以下の URL で対処法について詳しく記事を書いて下さっている方がいたお陰で、あっさり回避することができました。


submit_tagの :disable_withオプション - satake7’s memo
http://d.hatena.ne.jp/satake7/20090122


ただ、今度は disable_with と同時に、確認ダイアログを出す confirm オプションを指定した場合、確認ダイアログが出てくれません。

<%= submit_tag '送信', :disable_with => '送信中です...', :confirm => '送信してもよろしいですか?' %>


どうやらこのダイアログの出ない現象は、 IE のみではなく、Firefox(3.0.13)、Google Chrome(2.0.172.39) でも同様のようです。

この問題の為だけに Rails のバージョンを上げるというのも微妙なので、回避方法を調べていたところ、2.2.2 以上のバージョンでは既に修正されているようでした。


Commit 77f7d98e38dddf72890c80b4e4b2e088bb76d111 to rails's rails - GitHub
http://github.com/rails/rails/commit/77f7d98e38dddf72890c80b4e4b2e088bb76d111


修正内容的に satake7 さんの修正と合わせて適用できそうだったので、以下のように submit_tag をオーバーライドしました。
application_helper.rb に以下のコードを入れています。

module ActionView
  module Helpers
    module FormTagHelper
      def submit_tag(value = "Save changes", options = {})
        options.stringify_keys!

        if disable_with = options.delete("disable_with")
          disable_with = "this.value='#{disable_with}'"
          disable_with << ";#{options.delete('onclick')}" if options['onclick']

          # :disable_with オプションの IE 不具合のための修正
          #options["onclick"]  = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }"
          #options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }"
          options["onclick"] = "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};"
          options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());"
          options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;"
        end

        if confirm = options.delete("confirm")
          # confirmオプションとdisabled_withオプションの併用を可能とするための修正
          # options["onclick"] ||= ''
          # options["onclick"] << "return #{confirm_javascript_function(confirm)};"
          options["onclick"] ||= 'return true;'
          options["onclick"] = "if (!#{confirm_javascript_function(confirm)}) return false; #{options['onclick']}"
        end

        tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options.stringify_keys)
      end
    end
  end
end


これで無事期待通りの動作をしてくれるようになりました。


ちなみに、手元でサンプルを書いて確認したところ、どちらの現象も Rails 2.3.3 では発生しませんでした。