Ruby on rails Ember.js POST请求从服务器(GrapeAPI)返回400,但已成功存储到本地存储中

Ruby on rails Ember.js POST请求从服务器(GrapeAPI)返回400,但已成功存储到本地存储中,ruby-on-rails,ruby-on-rails-4,ember.js,grape,grape-api,Ruby On Rails,Ruby On Rails 4,Ember.js,Grape,Grape Api,几个小时以来,我一直在尝试让一个简单的Ember.js应用程序发布到GrapeAPI后端,但我似乎无法让它工作。我知道API是有效的,因为我可以通过Swagger文档向它发布新记录,并且它们是持久的。我知道API和Ember谈得很好,因为我可以从服务器获取所有记录并在页面上与它们交互,而且我知道Ember在真空中工作得很好,因为我的记录被保存到本地存储 然而,我似乎无法得到一个工作的职位要求。它总是返回一个400。我已经正确配置了Rack COR,并且在前端设置了ActiveModelAdapt

几个小时以来,我一直在尝试让一个简单的Ember.js应用程序发布到GrapeAPI后端,但我似乎无法让它工作。我知道API是有效的,因为我可以通过Swagger文档向它发布新记录,并且它们是持久的。我知道API和Ember谈得很好,因为我可以从服务器获取所有记录并在页面上与它们交互,而且我知道Ember在真空中工作得很好,因为我的记录被保存到本地存储

然而,我似乎无法得到一个工作的职位要求。它总是返回一个400。我已经正确配置了Rack COR,并且在前端设置了ActiveModelAdapter,在后端设置了ActiveModelSerializer

这是模型

Contact = DS.Model.extend {
  firstName: DS.attr('string'),
  lastName:  DS.attr('string'),
  email:     DS.attr('string'),
  title:     DS.attr('string'),
  createdAt: DS.attr('date'),
  updatedAt: DS.attr('date')
}
和控制器

ContactsNewController = Ember.ObjectController.extend(
  actions:
    save: ->
      @get('model').save()
    cancel: ->
      true
)
API的相关部分如下所示

desc 'Post a contact'
  params do
    requires :first_name, type: String, desc: 'First name of contact'
    requires :last_name , type: String, desc: 'Last name of the contact'
    requires :email     , type: String, desc: 'Email of the contact'
    requires :title     , type: String, desc: 'Title of the contact'
  end
  post do
    Contact.create!(
      first_name: params[:first_name],
      last_name:  params[:last_name],
      email:      params[:email],
      title:      params[:title]
    )
  end
我使用的表单是…

<form {{action 'save' on='submit'}}>
  <h2>{{errorMessage}}</h2>

  <label>First Name</label>
  {{input value=firstName placeholder='First Name' type='text' autofocus=true}}

  <label>Last Name</label>
  {{input value=lastName placeholder='Last Name' type='text'}}

  <label>Email</label>
  {{input value=email placeholder='Email' type='text'}}

  <label>Job Title</label>
  {{input value=title placeholder='Job Title' type='text'}}

  <hr>

  <input type='submit' value='Save'>
</form>
{"error":"first_name is missing, last_name is missing, email is missing, title is missing"}
有人要吗?对不起,我是新手。有些事情还没有解决,但我不知道为什么


更新 更多的调查

图像:

然而,当我从Ember发帖时,服务器的响应仍然是

{"error":"first_name is missing, last_name is missing, email is missing, title is missing"}
图片:

我还将控制器更改为…,这将在上面的chrome开发工具日志中提供输出

`import Ember from 'ember'`

ContactsNewController = Ember.ObjectController.extend(
  actions:
    createContact: ->
      firstName = @get('firstName')
      lastName  = @get('lastName')
      email     = @get('email')
      title     = @get('title')

    newRecord = @store.createRecord('contact', {
                   firstName: firstName,
                   lastName:  lastName,
                   email:     email,
                   title:     title
                 })

    self = this

    transitionToContact = (contact) ->
      self.transitionToRoute('contacts.show', contact)

    newRecord.save().then(transitionToContact)
   )

`export default ContactsNewController`

我对Ember.js一无所知,但我已经用Grape构建了一段时间的API,所以我想我可以帮你。查看您所附的图像,似乎Ember.js在有效负载中创建了一个不正确的JSON,而您的Grape API并不希望JSON以这种方式格式化。如第二幅图所示,它创建了一个JSON,如下所示:

{ contact: {...} }
{ first_name: "", last_name: "", email: "" }
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
});
但是,您的API需要类似以下的JSON格式:

{ first_name: "" ... }
现在,看看你是如何通过Chrome开发工具发送相同的请求的。。。您正在使用“表单数据”选项来创建主体请求,这就是为什么在这种特定情况下它会工作的原因。尝试将其更改为“raw”,并将不正确的JSON放在上面,您将得到与使用Ember.Js时相同的错误

我没有具体的解决方案,因为我没有专业知识来帮助您使用Ember.Js。。。但是,您必须更改Amber.js应用程序中的某些内容,使其创建一个JSON请求,如下所示:

{ contact: {...} }
{ first_name: "", last_name: "", email: "" }
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
});
而不是:

{ contact: { first_name: "" ... } }
希望它能帮助你

更新

解决问题的另一个方法是更改grapeapi。在这种情况下,您必须在params块中创建块,如下所示(考虑到联系人字段现在存储在params[:contact]散列中):


如果要更改Ember格式化JSON的方式,则需要创建自定义序列化程序并重写该函数。可以使用此方法自定义序列化到JSON中的根键。默认情况下,REST序列化程序发送模型的typeKey,这是名称的骆驼化版本

Ember cli附带用于启动序列化程序的生成器。您可以通过以下方式运行它:

 ember g serializer Contact
开箱即用的序列化程序如下所示:

{ contact: {...} }
{ first_name: "", last_name: "", email: "" }
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
});
要使其与葡萄一起使用,您可以执行以下操作:

import DS from 'ember-data';

export default DS.RESTSerializer.extend({
  serializeIntoHash: function(data, type, record, options) {
    var properties = this.serialize(record, options);
    for(var prop in properties){
      if(properties.hasOwnProperty(prop)){
        data[prop] = properties[prop];
      }
    }
  }
});

更多信息请参见。

能否显示Ember发送的请求(例如通过chrome控制台?)。你能使用curl来发出有效的POST请求吗?我对Grape一无所知,但看起来你的Ember模型中的字段是camelCase,但在你的后端,这些字段是下划线的。(firstName vs first_name)@ThomasBrus我添加了一个从Postman发送的成功cURL的图像,以及一个从Chrome开发工具输出查看的从ember发送的请求失败的图像。这一定是灰烬邮报的序列化错误,不是吗?因为从外观上看,API自己可以很好地处理它。@Griffosx我认为这是一个问题,但在文章的更新部分,我的输出JSON似乎被我在ember应用程序中设置的ActiveModelAdapter从camel正确地序列化为snake。在Rails中,我运行一个ActiveModelSerializer,当发送到Ember时,它还将所有JSON从snake转换为camel大小写;然而,我确实认为你是对的,我的Ember应用程序将数据发送回服务器的方式有问题,因为cURL正在工作(通过邮递员)。我同意@Griffosx的观点,即“简单”的方法是在两个方向上保持所有属性为snake_case。将模型修改为first_name等,然后去掉将数据更改为CamelCase的活动模型序列化程序。这绝对是问题所在。谢谢不过,我确实有一个问题。我将尝试更改Ember应用程序的JSON输出以及GrapeAPI接受的JSON。我担心,如果我更改Ember应用程序的JSON输出,它将与应用程序的默认行为冲突,而我自己构建了API;更有可能的是,我错误地为它接受的JSON命名了名称空间。可以用一个简短的示例来帮助我正确命名API的名称空间吗?我更改了答案,以向您展示如何修改API处理JSON的方式。好的,只有在将代码更改为(/n表示换行)\\params do/n group:contact,type:Hash do/n后,我才能使其正常工作。。。等等没有type:Hash,Grape认为我发送了一个数组,所以它不断抛出400-“contact”无效,但是使用type:Hash,它可以完美地进行。谢谢你的帮助。当您更新您的答案以反映此更改时,请告诉我,我将接受它作为解决方案。是的!你说得对。我忘了将type参数添加到“group”块中。我刚刚编辑了答案以反映这一变化。谢谢谢谢你的帮助!它现在运转得很好。