在Rails中是否有一种“标准”的方法来接收(可能嵌套)一个JSON:API POST对象?
JSON:API规范对GET / POST / PUT等使用相同的格式,但是rails似乎需要* _attributes和accepts_nested_attributes_for。这些似乎不兼容。
我觉得我做的事情一定很常见,但是我在查找文档时遇到了麻烦。我想使用React / Redux应用程序,该应用程序使用JSON:API规范与Rails应用程序进行通信。我只是不确定如何处理嵌套关联。
答案 0 :(得分:1)
您可以active_model_serializer gem的反序列化功能。
来自宝石的docs:
class PostsController < ActionController::Base
def create
Post.create(create_params)
end
def create_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:title, :content, :author])
end
end
以上内容可与以下JSON API有效负载配合使用:
document = {
'data' => {
'id' => 1,
'type' => 'post',
'attributes' => {
'title' => 'Title 1',
'date' => '2015-12-20'
},
'relationships' => {
'author' => {
'data' => {
'type' => 'user',
'id' => '2'
}
},
'second_author' => {
'data' => nil
},
'comments' => {
'data' => [{
'type' => 'comment',
'id' => '3'
},{
'type' => 'comment',
'id' => '4'
}]
}
}
}
}
可以在不指定任何选项的情况下解析整个文档:
ActiveModelSerializers::Deserialization.jsonapi_parse(document)
#=>
# {
# title: 'Title 1',
# date: '2015-12-20',
# author_id: 2,
# second_author_id: nil
# comment_ids: [3, 4]
# }
答案 1 :(得分:0)
几天前,我在JSON:API存储库上看到了这些冗长的主题讨论#979和#795,显然,看来JSON API并没有针对accepts_nested_attributes_for
的真正解决方案。
我不知道这是否是更好的解决方案,但是解决该问题的方法是为您的belongs_to
和has_many/has_one
关联分配路由。
类似的东西:
您的 routes.rb :
Rails.application.routes.draw do
resources :contacts do
resource :kind, only: [:show]
resource :kind, only: [:show], path: 'relationships/kind'
resource :phones, only: [:show]
resource :phones, only: [:show], path: 'relationships/phones'
resource :phone, only: [:update, :create, :destroy]
# These relationships routes is merely a suggestion of a best practice
resource :phone, only: [:update, :create, :destroy], path: 'relationships/phone'
resource :address, only: [:show, :update, :create, :destroy]
resource :address, only: [:show, :update, :create, :destroy], path: 'relationships/address'
end
root 'contacts#index'
end
他们实现您的控制器。 遵循上述示例的 phones_controller.rb :
class PhonesController < ApplicationController
before_action :set_contacts
def update
phone = Phone.find(phone_params[:id])
if phone.update(phone_params)
render json: @contact.phones, status: :created, location: contact_phones_url(@contact.id)
else
render json: @contact.errors, status: :unprocessable_entity
end
end
# DELETE /contacts/1/phone
def destroy
phone = Phone.find(phone_params[:id])
phone.destroy
end
# POST contacts/1/phone
def create
@contact.phones << Phone.new(phone_params)
if @contact.save
render json: @contact.phones, status: :created, location: contact_phones_url(@contact.id)
else
render json: @contact.errors, status: :unprocessable_entity
end
end
# GET /contacts/1/phones
def show
render json: @contact.phones
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contacts
@contact = Contact.find(params[:contact_id])
end
def phone_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params)
end
end
这样做,您应该通常可以通过联系人分别请求电话 POST ,如下所示:
POST在 http:// localhost:3000 / contacts / 1 / phone 上,正文:
{
"data": {
"type": "phones",
"attributes": {
"number": "(+55) 91111.2222"
}
}
}
http:// localhost:3000 / contacts / 1 / phones 上的响应或GET:
{
"data": [
{
"id": "40",
"type": "phones",
"attributes": {
"number": "(55) 91111.2222"
},
"relationships": {
"contact": {
"data": {
"id": "1",
"type": "contacts"
},
"links": {
"related": "http://localhost:3000/contacts/1"
}
}
}
}
]
}
希望这个答案