web-dev-qa-db-ja.com

Rails ajax呼び出し後にフラッシュメッセージを表示しません

Rails 4.0.2アプリを作成していて、AJAXイベントの後にFlash通知をビューに表示しようとしています。

私のビューでは、ユーザーがクリックできる日数のカレンダーを表示しています。その場合、モデルを更新するonclickイベントハンドラーを介してAJAXイベントを発生させ、レコードを追加または削除します。イベントを発生させた後、表示するためにページの更新を完了します。更新された結果。

ビューを適切に更新するには、JSクリックイベント中にページを更新する必要があることがわかりました。コントローラでのリダイレクトまたはレンダリングだけでは十分ではありませんでした。

そのため、コントローラーにFlash通知を設定しました...

def set_conflicts
  @conflict = @member.conflicts.for_date(params[:date]).first

  if @conflict
    @conflict.destroy
  else
    conflict_date = Date.parse(params[:date])
    unless Conflict.create(
        month: conflict_date.month,
        day:   conflict_date.day,
        year:  conflict_date.year,
        member: @member
    )
      flash[:alert] = 'Oops, there was a problem updating conflicts'
    end
  end
  flash[:notice] = 'This is a test!'
  redirect_to manage_member_conflicts_path(@member)
end

...そして私のapplication.haml ..に次のフラッシュ表示ロジックを含めました。

...
%body
  = p flash.inspect
  - flash.each do |type, message|
    = content_tag(:div, message, :class => "flash-#{type}")

  = render 'devise/menu/login_items'
  = yield

注:ビューでERBの代わりにHAMLを使用しています

それでも、何を試しても、Flashメッセージは表示されません。他のすべては期待どおりに機能しますexceptフラッシュメッセージ、そして私はwhyを理解することができませんでした。

リダイレクト(そしておそらくターボリンク)と組み合わせて行っているAJAXリフレッシュと関係があると思いますが、ここで他の回答を調べましたSOそして単にそれを機能させることができません。明らかに、私は何かが欠けています。

これがJSクリックハンドラーです(とても簡単です):

window.calendarClick = (eventDate, linkURL) ->
  event = $(document.getElementById(eventDate))
  event.toggleClass('selected')

  # Set or Remove conflicts
  $.ajax
    url: linkURL
    data:
      date: eventDate

  # Refresh the page
  $.ajax
    url: '',
    context: document.body,
    success: (s,x) ->
      $(this).html(s)
13
Donovan

まず、包括的な質問に感謝します

同様に包括的な答えは次のとおりです。 AjaxリクエストでRailのフラッシュをどのように処理しますか?


Ajax

Ajaxの更新プロセスを真剣に検討します。ページ全体を更新するのは非常に非効率的であり、より深い問題をカバーしていると思います

viewsフォルダーにある.js.erbファイルを使用して、次の方法でJSを直接処理してみませんか。

def set_conflicts
  @conflict = @member.conflicts.for_date(params[:date]).first

  if @conflict
    @conflict.destroy
  else
    conflict_date = Date.parse(params[:date])
    unless Conflict.create(
        month: conflict_date.month,
        day:   conflict_date.day,
        year:  conflict_date.year,
        member: @member
    )
      flash[:alert] = 'Oops, there was a problem updating conflicts'
    end
  end
  flash[:notice] = 'This is a test!'

  respond_to do |format|
      format.html { redirect_to manage_member_conflicts_path(@member) }
      format.js 
  end
end

#app/views/controller/set_conflicts.js.erb
$("#your_element").html(<%=j render manage_member_conflicts_path(@member) ) %>);

応答

これは確かにわかりませんが、Flashオブジェクトが ActionDispatch :: Flash ミドルウェアによって処理されることは知っています。これは、標準のHTTPリクエストと同じようにXHRで処理されないため、Flashが応答に表示されないようになると思います。

これは、Ajaxリクエストを介してFlashオブジェクトを渡すために何かをする必要があることを意味します。そして、この回答の上部に投稿した質問によると、response headersを使用してそれを行うことができます。

class ApplicationController < ActionController::Base
after_filter :flash_to_headers

def flash_to_headers
  return unless request.xhr?
  response.headers['X-Message'] = flash[:error]  unless flash[:error].blank?
  # repeat for other flash types...

  flash.discard  # don't want the flash to appear when you reload page
end

$(document).ajaxError(function(event, request) {
  var msg = request.getResponseHeader('X-Message');
  if (msg) alert(msg);
});
9
Richard Peck

ヘッダーにメッセージを渡す必要性は、何かを行うための大胆な方法のように思えたので、検討したいと思いますRailsはすでに可能であるはずです。

数時間検索した後、コントローラーに次の行を渡すことで、必要なことをすでに実行していることに気付きました。

flash[:error] = "My flash message error."

respond_to do |format|
  format.js 
end

Flash [:error]は、次のビューのFlashメッセージを設定します。respond_toは、remote:trueがlink_to(元のajaxリクエスト)に設定されていることを認識します。

<%= link_to "My Ajax Request", some_path(@some_value), remote: true %>

リンクにJavaScriptとして応答します。リモートをtrueに設定せずに同じコントローラーを呼び出す機能を引き続き使用したい場合は、このブロックにformat.htmlを含めることができます。

私のapplication.html.erbには、フラッシュメッセージをレンダリングするパーシャルがあります。

<%= render "layouts/flash_notices" %>

そのパーシャルには、次のようなdivが含まれています。

<div id="flash_messages">
  <% flash.each do |type, message| %>
    <p><%= type %>: <%= message %></p>
  <% end %>
</div>

最後に、MY_CONTROLLER_ACTION_NAME.js.erbというビューを作成し、次を挿入しました。

<% flash.each do |type, message| %>
  $("#flash_messages").html("<%= type.to_s.humanize %>: <%= message.html_safe %>")
<% end %>

AJAX enabledリンクをクリックすると、コントローラーアクションが実行され、フラッシュメッセージが設定され、コントローラーがjs.erbビューをロードし、最後にjavascriptをロードしてdivのコンテンツを置き換えます。 with id = "flash_messages"が実行されます。私の元のビューはフラッシュメッセージで更新され、すべてが世界で正しく行われます。

注:Bootstrapまたはその他の特別なCSSフレームワークを使用している場合は、そのコードをjs.erbファイルの$( "#flash_messages ')。html(" ");呼び出しに含めることができます。次のようにBootstrapコードを含めました:

$("#flash_messages').html("<div class='alert <%= bootstrap_class_for(type) %> alert-dismissible' role='alert'><button class='close' data-dismiss='alert'>×</button><%= message.html_safe %></div>")

この質問が数か月前に投稿されたことは知っていますが、この正確な問題を検索すると、ヘッダーを介してフラッシュメッセージを送信する必要があるという応答が常に表示されます。別の方法があることを示したかったのです。うまくいけば、これは私の仲間Rails未来の初心者に役立つでしょう!

22
Celsian