Ruby on rails Ember.js POST请求从服务器(GrapeAPI)返回400,但已成功存储到本地存储中
几个小时以来,我一直在尝试让一个简单的Ember.js应用程序发布到GrapeAPI后端,但我似乎无法让它工作。我知道API是有效的,因为我可以通过Swagger文档向它发布新记录,并且它们是持久的。我知道API和Ember谈得很好,因为我可以从服务器获取所有记录并在页面上与它们交互,而且我知道Ember在真空中工作得很好,因为我的记录被保存到本地存储 然而,我似乎无法得到一个工作的职位要求。它总是返回一个400。我已经正确配置了Rack COR,并且在前端设置了ActiveModelAdapter,在后端设置了ActiveModelSerializer 这是模型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
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”块中。我刚刚编辑了答案以反映这一变化。谢谢谢谢你的帮助!它现在运转得很好。