3

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

但是,我似乎无法让 POST 请求正常工作。它总是返回 400。我已经正确配置了 Rack-Cors,并且我在前端设置了一个 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"}

有接盘侠吗?对不起,我是新手。有些东西没有绑定,但我不知道为什么。


更新

更多调查...

图片:对 API cURL 的 POST 请求(通过 Postman)工作得很好。.

但是,当我从 Ember 发布时,服务器响应仍然是

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

图片:来自 Chrome 开发工具的 POST 请求的输出如下所示

我还将控制器更改为...,这为我提供了上面 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`
4

2 回答 2

5

我对 Ember.js 一无所知,但我已经使用 Grape 构建 API 有一段时间了,所以我想我可以帮助你。查看您附加的图像,Ember.js 似乎在 Payload 中创建了一个不正确的 JSON,而您的 Grape API 并不期望以这种方式格式化的 JSON。正如您在第二张图片中看到的那样,它正在创建一个这样的 JSON:

{ contact: {...} }

但是,您的 API 需要这样的 JSON 格式:

{ first_name: "" ... }

现在,看看您是如何通过 Chrome 开发工具发送相同的请求的……您正在使用“form-data”选项来创建正文请求,这就是为什么在这种特定情况下它可以工作的原因。尝试将其更改为“原始”并将错误的 JSON 放在上面,您将得到与使用 Ember.Js 相同的错误。

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

{ first_name: "", last_name: "", email: "" }

代替:

{ contact: { first_name: "" ... } }

希望对你有帮助!

更新

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

desc 'Post a contact'
params do
    group :contact, type: Hash 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
end
post do
    Contact.create!(
        first_name: params[:contact][:first_name],
        last_name:  params[:contact][:last_name],
        email:      params[:contact][:email],
        title:      params[:contact][:title]
    )
end
于 2014-11-12T19:34:54.797 回答
0

如果您想更改 Ember 格式化 JSON 的方式,您需要创建一个自定义序列化程序并覆盖serializeIntoHash函数。您可以使用此方法自定义序列化为 JSON 的根密钥。默认情况下,REST Serializer 发送模型的 typeKey,它是名称的骆驼化版本。

Ember-cli 带有一个用于启动序列化程序的生成器。您可以使用以下命令运行它:

 ember g serializer Contact

开箱即用,序列化程序将如下所示:

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];
      }
    }
  }
});

文档中的更多信息。

于 2015-03-01T12:25:10.430 回答