Как получить сообщение JSON: API о вложенных атрибутах в Ruby on Rails? - PullRequest
3 голосов
/ 16 мая 2019

Существует ли «стандартный» подход для получения (потенциально вложенного) объекта JSON: API POST в Rails?

Спецификация JSON: API использует тот же формат для GET / POST / PUT и т. Д., Но, похоже, для rails нужны * _attributes и acceptpts_nested_attributes_for.Они кажутся несовместимыми.

Мне кажется, что то, что я делаю, должно быть довольно распространенным явлением, но у меня возникают проблемы с поиском документации.Я хочу использовать приложение React / Redux, которое взаимодействует с приложением Rails с использованием спецификации JSON: API.Я просто не знаю, как обращаться с вложенными ассоциациями.

Ответы [ 2 ]

1 голос
/ 16 мая 2019

Вы можете active_model_serializer Функциональность десериализации gem.

Из документов камня:

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]
# }
0 голосов
/ 17 мая 2019

Я видел эти обсуждения длинных тем / проблем # 979 и # 795 на JSON: репо API несколько дней назад, очевидно, что JSON API не имеет истинного решения для accepts_nested_attributes_for.

Я не знаю, является ли это лучшим решением, но обходной путь к этому - избавиться от маршрута к вашим belongs_to и has_many/has_one ассоциациям.

Примерно так:

Ваш rout.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"
            }
    }
}

Ответ или GET на http://localhost:3000/contacts/1/phones:

{
    "data": [
        {
            "id": "40",
            "type": "phones",
            "attributes": {
                "number": "(55) 91111.2222"
            },
            "relationships": {
                "contact": {
                    "data": {
                        "id": "1",
                        "type": "contacts"
                    },
                    "links": {
                        "related": "http://localhost:3000/contacts/1"
                    }
                }
            }
        }
    ]
}

Надеюсь, что ответ

...