HABTM 与 rails API 的关系无效

HABTM relationship with rails API does not work

我是 Rails Ruby 的新人。我正在使用 Rails 5.1、活动记录序列化程序、门卫和设计 gem.

制作 Rails API

我有一个 Order table,它有很多产品。订单和产品是多对多的关系。

订购型号:

class Order < ApplicationRecord      
  validates_presence_of :brute, :net
  has_and_belongs_to_many :products      
end

产品型号:

class Product < ApplicationRecord
  belongs_to :category
  validates_presence_of :name, :price
  validates_uniqueness_of :name
  has_and_belongs_to_many :orders
end

我有一个名为 orders_products 的连接 table。

订单序列化程序:

class OrderSerializer < ActiveModel::Serializer
  attributes :id, :discount, :brute, :net, :payed, :payed_at, :products      

  def products
    object.products.map do |product|
      ProductSerializer.new(product, scope: scope, root: false, event: object)
    end
  end

end

产品序列化程序:

 class ProductSerializer < ActiveModel::Serializer
  attributes :id, :name, :price, :description
  has_one :category
end

订单控制器:

module Api
  class OrdersController < ApiController
    before_action :set_order, only: [:show, :update, :destroy]

    # GET /api/orders
    def index
      @orders = Order.all

      render json: @orders
    end

    # GET /api/orders/1
    def show
      render json: @order
    end

    # POST /api/orders
    def create
      @order = Order.new(order_params)

      if @order.save
        render json: @order, status: :created, location: api_order_url(@order)
      else
        render json: @order.errors, status: :unprocessable_entity
      end
    end

    # PATCH/PUT /api/orders/1
    def update
      if @order.present?
        if @order.update(order_params)
          render json: @order
        else
          render json: @order.errors, status: :unprocessable_entity
        end
      end
    end

    # DELETE /api/orders/1
    def destroy
      @order.destroy if @order.present?
    end

    private
    # Use callbacks to share common setup or constraints between actions.
    def set_order
      @order = Order.find(params[:id])
    rescue ActiveRecord::RecordNotFound
      Rails.logger.error{ 'Order record is not found' }
      nil
    end

    # Only allow a trusted parameter "white list" through.
    def order_params
      params.require(:order).permit(:discount, :brute, :net, :payed, :payed_at, product_ids: [])
    end
  end
end

当我post从API生成器应用Postman/Insomnia订购json数据时,订单被保存在订单table中,但没有保存数据在 orders_products 加入 table.

我的请求(POST http://localhost:3000/api/orders) 订单json:

{
        "discount": 110,
        "brute": 100,
        "net": 200,
        "payed": null,
        "payed_at": null,          
        "product_ids": [3]
}

我试图找到解决方案,但我失败了。

据我所知,Rails 不会在给定 ID 列表时自动处理连接记录的创建。因此,当您调用 @order = Order.new(order_params) 并期望它知道如何处理 product_ids: [3] 时,它只是忽略了它。

如果您使用以下内容修改 create 端点,您应该会看到正在创建的加入记录。

# POST /api/orders
def create
  @order = Order.new(order_params)

  if @order.save
    # Find products
    @products = Product.where(id: order_params[:product_ids])
    # Create join table records
    @products.each { |product| product.orders << order }

    render json: @order, status: :created, location: api_order_url(@order)
  else
    render json: @order.errors, status: :unprocessable_entity
  end
end

这只是一种不进行任何错误检查的可能解决方案。根据您的应用程序所需的安全性和稳健性,您可能需要创建一个服务来包装它并处理在创建订单和关联记录之前验证是否找到了产品。

编辑:OrderSerializer

验证连接 table 记录是否正确创建后。检查你的序列化器是否正常工作,它们有很好的文档。我相信你可以用这个替换 OrderSerializer 中当前的 products 方法:

class OrderSerializer < ActiveModel::Serializer
  attributes :id, :discount, :brute, :net, :payed, :payed_at, :products      

  def products
    object.products.map do |product|
      ProductSerializer.new(product).serializable_hash
    end
  end

end

我终于解决了你的 problem.Just 在你的模型中添加一个属性。

订购型号:

class Order < ApplicationRecord
  attribute :product_ids
  validates_presence_of :brute, :net
  has_and_belongs_to_many :products      
end

订单序列化程序:

class OrderSerializer < ActiveModel::Serializer
  attributes :id, :discount, :brute, :net, :payed, :payed_at
  has_many :products
end

并按照您的顺序创建方法 api:

# POST /api/orders
    def create
      @order = Order.new(order_params)

      if @order.save
        # Find products
        @products = Product.where(id: order_params[:product_ids])
        # Create join table records
        @products.each { |product| product.orders << @order }

        render json: @order, status: :created, location: api_order_url(@order)
      else
        render json: @order.errors, status: :unprocessable_entity
      end
    end

我已经在本地测试过了,可以用!快乐编程:)