2017-10-09 72 views
2

我是Ruby on Rails中的新成员。我正在使用Rails 5.1,活动记录序列化器,门卫和设计宝石制作Rails API。与rails API的HABTM关系不起作用

我有一个Order表,它有许多产品。订单和产品之间的关系是多对多的。

订货型号:

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连接表。

订购串行:

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 

当我发布的API生成器应用中的一些秩序JSON数据,如邮差/失眠,订单正在保存在订单表中,但没有保存在orders_products连接表中的数据。

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

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

我试图找到解决办法,但我失败了。

+0

我不使用序列化程序,所以我不太熟悉你的一些代码。虽然您可以指出您的代码中的哪个位置可以将产品添加到您的订单中吗?也许你可以复制视图(erb)文件,在这里处理太多.. – Maxence

+0

我也面临同样的问题。但是在使用活动记录序列化程序gem时没有erb文件。 –

回答

1

最后,我在你的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 

我在本地已经测试和它的作品!快乐编程:)

+0

谢谢@Engr。坦比尔哈桑,你应该得到一枚奖牌。 –

0

据我所知,当给定一个id列表时,Rails不会自动处理创建连接记录。因此,当你打电话给@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

一旦你验证正在正确创建的连接表中的记录。检查你的序列化程序是否正常工作,他们有很好的文档。我相信你可以在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 
+0

order_params [:product_ids]当我从json API请求时返回nil。为什么? –

+0

这听起来像是你有两个问题。第一个问题是连接表记录没有被创建。我上面介绍的解决方案应该解决这个问题,您是否证实现在正在创建记录?如果他们是和你的JSON输出仍然不正确,那么你的序列化器是错误的。添加上面的信息。 – Genzume

+0

您提供的方法是正确的,我检查了它@products = Product.where(id:3),然后连接表正在创建。但是当我调试并发现order_params [:product_ids]总是返回nil并且order_params不包含任何product_ids!我的json格式不正确? 你的'serializable_hash'返回错误,它需要两个缺失的参数。 –