【问题标题】:Why is my Rails Controller expecting JSON from the format.js call?为什么我的 Rails 控制器需要来自 format.js 调用的 JSON?
【发布时间】:2015-08-14 03:30:20
【问题描述】:

我正在使用 Bootstrap 3 模式和 AJAX 向我的 Rails 应用程序添加一个新的 Sale_Contact。它不起作用 - 我从服务器返回 200 OK 代码,并且正在将对象添加到数据库中,但是因为没有返回 JSON(创建操作只是发回 create.js.erb 文件到 JQuery.parse.json 操作)然后我触发 ajaxError 而不是 ajaxSuccess,我的模式没有关闭,并且使用新的 sale_contact 对象更新视图的 javascript 没有执行。

我不明白为什么我的 Rails 控制器期望在这个实例中返回一个 Json 对象——我基本上是直接从我也用模态和 AJAX 构建的其他对象复制了这段代码,它们都运行良好。谁能帮我理解在这种情况下出了什么问题?

我的控制器:

  def create
   @sale_contact = SaleContact.new(sale_contact_params)
   @sales_opportunity = @sale_contact.sales_opportunity

respond_to do |format|
  if @sale_contact.save
    #format.html { redirect_to @sale_contact.sales_opportunity, notice: 'Sale contact was successfully created.' }
    format.js 
    #format.json { render json :show, status: :created, location: @sale_contact }
  else
    format.html { render :new }
    format.json { render json: @sale_contact.errors, status: :unprocessable_entity }
    format.js { render json: @sale_contact.errors, status: :unprocessable_entity }
  end
 end
end

我已经对此进行了测试,我可以看到 if @sale_contact.save 块正在运行。正如您在上面看到的,我还注释掉了 format.html 和 format.json 行,但这不会改变结果。

我的 Sale_Contacts 的 create.js.erb 文件:

    console.log('anything at all');
    //update the selection list with the new sale contact, and close the modal
    $('#sales_opp_sale_contact_modal').modal('hide')
                    .clear_previous_errors();
    resetForm($('#new_sale_contact'));
    $input = $('#contact_error');
    $input.closest('.form-group').removeClass('has-error').find('.warning-block').html('');
  //render the newly added sale contact to the table if the AJAX call succeeded
   console.log('fired');
   $(document).ajaxSuccess(function() {
    $( ".log" ).text( "Triggered ajaxSuccess handler. The ajax response was: " +
  xhr.responseText );
    $('#sales-opp-key-contacts-table-div').html("<%= escape_javascript(render :partial => 'sale_contacts/table')%>");
    //console.log(document);
    $('.alert').remove();
    $('.navbar-default .navbar-nav > li > a').removeClass('selected');
    $('#sale-contacts').DataTable({
        retrieve: true,
});

此代码永远不会触发 - 而是将其传递回 ajaxError 函数:

Uncaught SyntaxError: Unexpected token c
jQuery.parseJSON @ jquery.js?body=1:8483
(anonymous function) @ organizations.js?body=1:23
jQuery.event.dispatch @ jquery.js?body=1:4642
jQuery.event.add.elemData.handle @ jquery.js?body=1:4310
jQuery.event.trigger @ jquery.js?body=1:4551
done @ jquery.js?body=1:9286
jQuery.ajaxTransport.send.callback @ jquery.js?body=1:9686

如你所见,我的 create.js.erb 文件开始的“c”字符被传入,它不是有效的 JSON,因此会抛出 parseError。

我添加了一些新代码来查看从 ajaxError 中返回的项目 - 以防这些帮助:

$(document).ready(function(){
 $(document).on('ajaxError', function(XMLHttpRequest, textStatus, errorThrown){
 console.log("some error" + errorThrown);
 });
 $(document).on('ajaxError', function(req, xhr, err){ 
  console.log('my message' + err + xhr.status);
 });
 $(document).bind('ajaxError', function(event, jqxhr, settings, exception){

// note: jqxhr.responseJSON undefined, parsing responseText instead
console.log(jqxhr.responseText)
$(event.data).render_form_errors( $.parseJSON(jqxhr.responseText) );
});

由此产生的输出是:

some error[object Object]
my message[object Object]200
console.log('anything at all');
//update the selection list with the new sale contact, and close the modal
$('#sales_opp_sale_contact_modal').modal('hide')
                    .clear_previous_errors();
resetForm($('#new_sale_contact')); .....

为了简洁起见,我已对此进行了编辑,您可以看到前两个响应显示我正在发回对象(我如何找出哪个?)和 200 OK 代码,responseText 是 create.js。 erb 文件不会被触发。

我要疯了,想弄清楚为什么这不起作用。此对象与我以这种方式创建的其他对象之间的唯一区别是我的 Sale_Contact 是一个连接表(它属于 Sales_Opportunities 和 Key_Contacts,因此它们具有_many_through 这个表)。

如果重要的话,这里是模型:

class SaleContact < ActiveRecord::Base
 validates :key_contact_id, presence: true
 validates :sales_opportunity_id, presence: true
 belongs_to :key_contact
 belongs_to :sales_opportunity
 enum role: [ :not_known, :evaluator, :decision_maker, :budget_holder ]
 enum preference: [ :unknown, :supporter, :enemy ]
end

这是我的 sale_contacts/show.json.jbuilder 文件:

json.extract! @sale_contact, :id, :key_contact_id, :sales_opportunity_id, :role, :preference, :created_at, :updated_at

任何帮助将不胜感激

快速编辑 这是我的相关项目的 routes.rb 文件,我希望这可能是问题:

  resources :sales_opportunities do
   resources :timeline_events, shallow: true
   resources :swots, shallow: true
   resources :sale_contacts, shallow: true
 end

第二次修改

就像写这篇文章的一个想法一样,我在我的其他模式中对 ajaxSuccess 事件进行了相同的 ajax 分析 - 它们也返回与上面完全相同的信息:

some error[object Object]
my message[object Object]200
whatever create.js.erb template was added successfully

所以问题不是来自服务器的返回——还有其他问题。我正在使用 Bootstrap 3 模态,所以也许我需要深入研究他们的 ajax 代码才能找到问题。

编辑 3 - 添加模态内容

<%= form_for(@sale_contact, :html => {role: :form, 'data-model' => 'sale_contact'}, remote: true) do |f| %>
<% if @sale_contact.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@sale_contact.errors.count, "error") %> prohibited this sale_contact from being saved:</h2>

  <ul>
  <% @sale_contact.errors.full_messages.each do |message| %>
    <li><%= message %></li>
   <% end %>
   </ul>
  </div>
<% end %>

<div class="form-group" id= "contact_error">
  <%= f.label :key_contact_id, :class => "control-label" %>
  <div id="contact_select">
  <%= f.collection_select :key_contact_id, @sales_opportunity.company.key_contacts(:full_name), :id, :full_name %>
  </div>
   <span class="warning-block"></span>
   <span class="help-block"></span>
  </div>

<div class="form-group">
  <%= f.label :role, :class => "control-label" %>
  </br>
    <%= f.select(:role, options_for_select(@roles.collect { |r| [r[0].humanize, r[0]] }, selected: @sale_contact.role), {}) %>
  <span class="help-block"></span>
</div>

<div class="form-group">
  <%= f.label :preference, :class => "control-label" %>
  </br>
    <%= f.select(:preference, options_for_select(@preferences.collect { |r| [r[0].humanize, r[0]] }, selected: @sale_contact.preference), {}) %>
  <span class="help-block"></span>
</div>


<div class="form-group">
  <%= f.hidden_field :sales_opportunity_id, :value => @sales_opportunity.id %>
</div>
  <%= f.submit "Save", class: "btn btn-large btn-success" %>
<% end %>

为了清楚起见 - 我为网站上的所有模式使用完全相同的模式布局(目前大约有 8 个工作),我只是剪切/粘贴代码并更改名称。 Modal 工作 - 一个新对象被持久化在数据库中 - Jquery 是问题所在。

【问题讨论】:

  • js 来确认这个 url 是如何从视图中调用的。通过放置remote: true,在链接中或来自JQuery ajax 请求或其他东西。
  • 是的,我在模态中调用 remote: true - 我将更新问题的内容以包含它。
  • 那个 format.js 的实际响应体是什么?
  • 对不起@SergioTulentsev - 你需要知道什么?来自 sale_contact 控制器的 format.js 的响应正文?如果是这样,那么我在 sale_contacts/create.js.erb 中有一个文件,由 format.js 行调用。响应正文包含 create.js.erb 文件的完整输出以及其中包含新对象的渲染部分 - 但这仅记录在控制台中。
  • 啊,什么是请求/响应标头,尤其是Content-Type?我怀疑是application/json

标签: javascript jquery ruby-on-rails ajax json


【解决方案1】:

最后我解决了这个问题 - 我使用this post 中描述的方法来隔离我的 create.js.erb 文件的问题。我还不得不删除该行

$('#sales-opp-key-contacts-table-div').html("<%= escape_javascript(render :partial => 'sale_contacts/table')%>");

从我的 javascript 中返回的部分只是为 firebug 控制台留下了太多的文本/噪音以提供帮助。当我这样做时,我注意到我错过了 });从 create.js.erb 文件的末尾开始 - 这意味着 javascript 返回了一个错误并抛出了 ajax.error 函数。

我觉得自己浪费了这么多的生命和精力来修复一个简单的语法错误——但我确实在练习期间学到了很多关于 JQuery、AJAX、Rails 控制器和调试的知识。

【讨论】:

    猜你喜欢
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 2012-07-10
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    相关资源
    最近更新 更多