【问题标题】:Make ajax POST and return JSON in Rails在 Rails 中制作 ajax POST 并返回 JSON
【发布时间】:2017-11-11 03:35:19
【问题描述】:

我正在尝试向我的一条路由发出 AJAX POST 请求并返回一些 JSON,但我遇到了一个问题,即没有返回 JSON,而是像 GET 请求一样呈现页面。这是我的代码:

查看

<%= form_with url: users_add_skill_path, id: "skills-form", format: 'json' do |f| %>
  <%= f.text_field :skill, placeholder: "Submit your skill" %>
  <%= f.submit "Submit Skill" %>
<% end %>

这变成了 HTML:

<form id="skills-form" action="/users/add_skill" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="token_hereadnfjahbsdkfjabsd">
    <label for="skill">Skill</label> 
    <input placeholder="Submit your skill" type="text" name="skill">

    <input type="submit" name="commit" value="Submit Skill" data-disable-with="Submit Skill">

</form>

路线

devise_scope :user do
    post '/users/add_skill' => 'users/registrations#add_skill', :defaults => 
{ :format => :json }
end

控制器

class Users::RegistrationsController < Devise::RegistrationsController

respond_to :html, except: [:add_skill]
respond_to :json, only: [:add_skill]    

def add_skill
  @user = current_user
  @user.skills.push(params[:skill])

  respond_to do |format|
    if @user.save
      format.json { render json: @user.skills, status: :created, location: @user }
    else
      format.json { render json: @user.errors, status: :unprocessable_entity }
  end
end

Javascript

const skillsForm = document.getElementById("skills-form");
skillsForm.addEventListener('ajax:success', function(res) {
    console.log("added skill"); 
});

“技能”被持久化到数据库中,所以我知道请求正在正确发出 - 如果我从路由中删除 :defaults =&gt; { :format =&gt; :json},并更改 respond_to 块中的其他一些内容(对不起我不记得我到底改变了什么),数据是持久的,页面没有改变,所以我很确定 Ajax 请求运行良好,但我不知道如何获得响应。

我看到很多使用 jQuery ajax() 的问题,但我没有使用 jQuery,所以我不确定我应该做什么。任何帮助将不胜感激!

【问题讨论】:

    标签: ruby-on-rails json ajax devise


    【解决方案1】:

    我实际上意识到我没有在我的 application.js 中包含rails-ujs,因此该请求是作为 GET 请求发出的,并且没有返回任何内容。现在一切都已解决,感谢您的帮助。

    【讨论】:

      【解决方案2】:

      当您使用 respond_to 时,您应该尝试使用 respond_with 返回 json,例如

      class SomeController < ApplicationController
        respond_to :json
      
      
        def show
          @record = Record.find params[:id]
      
          respond_with @record
        end
      end
      

      ,如果仍然无法正常工作,请尝试添加方法: :post 到您的表单并尝试。

      【讨论】:

      • 感谢您的回复。我尝试了这个并且没有任何改变,提交表单仍然会将我发送到显示 JSON 的新 url。我的表单在 HTML 中已经有 method="post"。
      • 你到底想要什么?你的问题能说清楚吗?
      • 我希望从 AJAX 调用返回 JSON,而不是带我到新页面查看 JSON。
      • 所以尝试删除respond_to do格式,只需respond_with @user.skills.if not try format.js under your previous code
      • 也尝试使用 event.preventDefault();在你的 ajax 请求中
      【解决方案3】:

      您的 ajax 代码看起来不错,但我在您的操作add_skill 中发现了一些问题。您正在尝试仅通过属性哈希将新技能推送到当前用户的现有技能。而是在用户的技能集合中构建技能并尝试像这样保存用户属性:

      def add_skill
        @user = current_user
        @user.skills.build(skill: params[:skill])
      
        respond_to do |format|
          if @user.save
            format.json { render json: @user.skills, status: :created, location: @user }
          else
            format.json { render json: @user.errors, status: :unprocessable_entity }
          end
        end
      end
      

      • push(*records):将一个或多个records 添加到集合中,方法是将它们的外键设置为关联的主键。您提供给push 的参数将导致ActiveRecord::AssociationTypeMismatch: Skill expected, got 'params[:skill]' which is an instance of String。有效方式可能如下所示:

      @user.skills.push(Skill.new(skill: params[:skill]))

      • build(attributes = {}, &block):返回一个集合类型的新对象,该对象已经用attributes 实例化并链接到该对象,但尚未保存。如果您使用这种方法,那么 respond_to 块会更有意义,因为在您调用 @user.save 之前不会保存用户技能。

      【讨论】:

      • 谢谢,您的意思是我应该专门为技能创建一个新模型并将它们与用户相关联吗?
      • 您肯定可以这样做。但上述解决方案也应该有效,没什么大不了的:)
      • 与我原来的解决方案相比,采用上述方式有什么好处?
      • 这与利益无关。请在上面更新的答案中查看buildpush 之间的区别。
      • 我明白了。在我的例子中,技能不是模型,它现在只是一个字符串。所以 push 工作得很好,但我确实有计划最终将它变成一个模型,所以我会记住这一点,谢谢!
      【解决方案4】:

      首先,在您的 eventListener 中将 ajax:success 替换为 ajax:complete

      您应该在表单 html 参数中添加remote: true,然后,您的请求将以您想要的格式响应(默认应为 'JS')

      例如:format: js,在你的控制器中做

      respond_to do |format|
        format.js { # TODO block }
      end
      

      最后使用send_data,您可以将数据发送到您的 Ajax 回调

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-28
        • 2018-07-14
        相关资源
        最近更新 更多