2017-10-09 6 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

私も同じ問題に直面しています。しかし、アクティブレコードシリアライザの宝石を使用している間はerbファイルはありません。 –

答えて

1

は、最後に私はあなたのモデル内の属性を追加するには、problem.Justで解決している:私はあなたがこれでOrderSerializerであなたの現在のproducts方法を入れ替えることができると信じて。

注文モデル:

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。 Tanbir Hasan、あなたはメダルに値する。 –

0

私が知る限り、Railsはidsのリストが与えられたときに結合レコードの作成を自動的には処理しません。したがって、@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 

これはエラーチェックを行わない1つの解決策に過ぎません。アプリケーションの安全性と堅牢性に応じて、これをラップするサービスを作成し、注文を作成してレコードを関連付ける前に製品が見つかったことを検証する必要があります。

EDIT:あなたが参加するテーブルのレコードが正しく作成されていることを確認したらOrderSerializer

。シリアライザが動作していることを確認してください。

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

json APIからリクエストしたとき、order_params [:product_ids]はnilを返します。どうして ? –

+0

2つの問題があるようです。最初の問題は、結合テーブルのレコードが作成されていないことです。私が上に示した解決策は、それを修正する必要があります、レコードが作成されていることを確認しましたか?それらがあり、あなたのjson出力が間違っている場合は、Orderシリアライザが間違っています。上記の情報を追加する。 – Genzume

+0

あなたの指定されたメソッドは正しいです、私は@products = Product.where(id:3)をチェックし、次に結合テーブルが作成されています。しかし、私がデバッグして見つけたとき、order_params [:product_ids]は常にnilを返し、order_paramsはproduct_idsを一切含んでいません!私のjson形式は間違っていますか? 'serializable_hash'はエラーを返します。欠落している引数が2つ必要です。 –

関連する問題