Mahesh Mesta Mahesh Mesta - 4 months ago 22
Ruby Question

Has_many through associated json data sent through postman not getting populated in the database in rails 4

I am trying to make a Post request through Postman which send my vendor model attributes and values and vendor_products model attributes.My json data looks like this

{
"name": "Raghu",
"email": "raghu@gmail.com",
"phone": "9008849042",
:
:
"vendor_products_attributes":
{
[{"product_id" : 7, "copies" : 8},
{"product_id" : 8, "copies" : 10}]
}
}


Now all my vendor model fields get populated, but vendor_products models are not been populated.I have used a nested form and nested attributes for vendors and vendor_products

My associations are as follows

A vendor ->

has_many :vendor_products
has_many :products, through: :vendor_products


A product ->

has_many :vendor_products
has_many :vendors, through: :vendor_products


A vendor_product

belongs_to :vendor
belongs_to :product


Vendor.rb

class Vendor < ActiveRecord::Base
has_many :vendor_products
has_many :products, through: :vendor_products
accepts_nested_attributes_for :vendor_products, :products,
:allow_destroy => true
end


My vendors/_form.html.erb

<%= form_for(@vendor) do |f| %>
<% if @vendor.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@vendor.errors.count, "error") %> prohibited this
vendor from being saved:</h2>

<ul>
<% @vendor.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
:
:
:
<%= f.fields_for :vendor_products do |vproducts| %>
<div class="field">
<%= vproducts.label :product %><br>
<%= vproducts.select :product_id,
options_from_collection_for_select(Product.all, "id", "product_name"),
prompt: "Select something" %>
<div class="field">
<%= vproducts.label :copies %><br>
<%= vproducts.number_field :copies %>
</div>
<% end %>

<div class="actions">
<%= f.submit %>
</div>
<% end %>


My vendors_controller.rb

class VendorsController < ApplicationController
before_action :set_vendor, only: [:show, :edit, :update, :destroy]
respond_to :json

def index
@vendors = Vendor.all.limit(20)
end


def show
end


def new
@vendor = Vendor.new
@product = @vendor.products.build
@vendor.vendor_products.build
end


def edit
end


def create
@vendor = Vendor.new(vendor_params)

respond_to do |format|
if @vendor.save
format.html { redirect_to @vendor,
notice: 'Vendor was successfully created.' }
format.json { render :show, status: :created, location: @vendor
}
else
format.html { render :new }
format.json { render json: @vendor.errors, status:
:unprocessable_entity }
end
end
end


def update
respond_to do |format|
if @vendor.update(vendor_params)
format.html { redirect_to @vendor, notice: 'Vendor was
successfully updated.' }
format.json { render :show, status: :ok, location: @vendor }
else
format.html { render :edit }
format.json { render json: @vendor.errors, status:
:unprocessable_entity }
end
end
end



private

def set_vendor
@vendor = Vendor.find(params[:id])
end

def vendor_params
params.require(:vendor).permit(:name, :email, :phone_no,
:addressline1,
:addressline2, :landmark,
:city, :state, :country, :pincode, :latitude, :longitude, :status,
product_attributes: [:product_id, :product_name, :price ],
vendor_products_attributes: [:vendor_product_id, :vendor_id,
:product_id,
:copies])
end
end


routes.rb

Rails.application.routes.draw do

match '/vendors/create_vendor' => 'vendors#create' , via: [:post]

resources :vendor_products
resources :products
resources :vendors
end


My server logs

Started POST "/vendors/create_vendor" for 127.0.0.1 at 2016-07-29
15:03:43 +0530
Processing by VendorsController#create as */*
Parameters: {"name"=>"Ragtyh", "email"=>"mahesh8mesta@gmail.com",
"phone_no"=>"9008849042", "addressline1"=>"#7, Varsha Pg",
"addressline2"=>"23rd main marenhalli, JP nagar 2nd phase",
"landmark"=>"opp mayura sweets", "city"=>"Bangalore",
"state"=>"Karnataka", "country"=>"India", "pincode"=>"560078",
"latitude"=>12.898773, "longitude"=>77.5764094, "status"=>true,
"vendor_products_attributes"=>[{"product_id"=>9, "copies"=>2},
{"product_id"=>7, "copies"=>3}], "vendor"=>{"name"=>"Ragtyh",
"email"=>"mahesh8mesta@gmail.com", "phone_no"=>"9008849042",
"addressline1"=>"#7, Varsha Pg", "addressline2"=>"23rd main marenhalli,
JP nagar 2nd phase", "landmark"=>"opp mayura sweets",
"city"=>"Bangalore", "state"=>"Karnataka", "country"=>"India",
"latitude"=>12.898773, "longitude"=>77.5764094, "status"=>true,
"pincode"=>"560078"}}
[1m[35m (0.2ms)[0m BEGIN
[1m[36mSQL (0.5ms)[0m [1mINSERT INTO "vendors" ("name", "email",
"phone_no", "addressline1", "addressline2", "landmark", "city", "state",
"country", "pincode", "latitude", "longitude", "status", "created_at",
"updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12,
$13, $14, $15) RETURNING "id"[0m [["name", "Ragtyh"], ["email",
"mahesh8mesta@gmail.com"], ["phone_no", "9008849042"], ["addressline1",
"#7, Varsha Pg"], ["addressline2", "23rd main marenhalli, JP nagar 2nd
phase"], ["landmark", "opp mayura sweets"], ["city", "Bangalore"],
["state", "Karnataka"], ["country", "India"], ["pincode", "560078"],
["latitude", 12.898773], ["longitude", 77.5764094], ["status", "t"],
["created_at", "2016-07-29 09:33:48.844763"], ["updated_at", "2016-07-29
09:33:48.844763"]]
[1m[35m (0.7ms)[0m COMMIT
Redirected to http://localhost:3000/vendors/100025
Completed 302 Found in 5592ms (ActiveRecord: 1.4ms)


While the raw json data in postman populates the vendor table, the vendor_products are not populating or been created. How can I solve this.Please note that I am a rails newbie

Answer

Gone through your code and all your code is correct, but the issue seems to be there in the request you are making to the controller through the postman.

In the request json file you do-not have the vendor key at all, so as you can see your logs, the vendor_products are not inside the vendor hash.

"vendor_products_attributes"=>[{"product_id"=>9, "copies"=>2}, {"product_id"=>7, "copies"=>3}]

this should ne inside the vendor hash,

So your JSON should look something like this,

{
"vendor": {
   "name": "Raghu",
   "email": "raghu@gmail.com",
   "phone": "9008849042",
     :
     :
   "vendor_products_attributes":
      {
        [{"product_id" : 7, "copies" : 8},
         {"product_id" : 8, "copies" : 10}]
      }
    }
  } 

To achive this, you should take some thing like,

  vendor[:name] = ""
  vendor[:name] = ""
  vendor[:phone] = ""
  ...

  ...
  vendor[:vendor_products_attributes][product_id][] = 7
  vendor[:vendor_products_attributes][copies][] = 10
  vendor[:vendor_products_attributes][product_id][] = 8
  vendor[:vendor_products_attributes][copies][] = 15

from your postnam.