PUT with a nested object

I have Dish and Comment models as shown below in my Rails 5.1 API application - the repo code is here . I need help adding a new Comment to Dish .

Message

 class Dish < ApplicationRecord has_many :comments end 

A comment

 class Comment < ApplicationRecord belongs_to :dish end 

Mail Serializer (uses ActiveModel Seriazlier)

 class DishSerializer < ActiveModel::Serializer attributes :id, :name, :image, :category, :label, :price, :featured, :description, :created_at has_many :comments end 

Comment serializer

 class CommentSerializer < ActiveModel::Serializer attributes :id, :rating, :comment, :author, :date def date object.created_at end end 

Mail controller - rails scaffold by default

 class DishesController < ApplicationController before_action :set_dish, only: [:show, :update, :destroy] # GET /dishes def index @dishes = Dish.all render json: @dishes end # GET /dishes/1 def show render json: @dish end # POST /dishes def create @dish = Dish.new(dish_params) if @dish.save render json: @dish, status: :created, location: @dish else render json: @dish.errors, status: :unprocessable_entity end end # PATCH/PUT /dishes/1 def update # byebug if @dish.update(dish_params) render json: @dish else render json: @dish.errors, status: :unprocessable_entity end end # DELETE /dishes/1 def destroy @dish.destroy end private # Use callbacks to share common setup or constraints between actions. def set_dish @dish = Dish.find(params[:id]) end # Only allow a trusted parameter "white list" through. def dish_params params.require(:dish).permit(:name, :image, :category, :label, :price, :featured, :description) end end 

Comment controller - rails scaffold by default

 class CommentsController < ApplicationController before_action :set_comment, only: [:show, :update, :destroy] # GET /comments def index @comments = Comment.all render json: @comments end # GET /comments/1 def show render json: @comment end # POST /comments def create @comment = Comment.new(comment_params) if @comment.save render json: @comment, status: :created, location: @comment else render json: @comment.errors, status: :unprocessable_entity end end # PATCH/PUT /comments/1 def update if @comment.update(comment_params) render json: @comment else render json: @comment.errors, status: :unprocessable_entity end end # DELETE /comments/1 def destroy @comment.destroy end private # Use callbacks to share common setup or constraints between actions. def set_comment @comment = Comment.find(params[:id]) end # Only allow a trusted parameter "white list" through. def comment_params params.require(:comment).permit(:rating, :comment, :author) end end 

Question

When the user visits /dishes/:id and adds a comment to the plate through an external application (Angular 2), Comment clicks on the array of current comments, and I call PUT /dishes:id with a Dish object embedded in the existing comments and the new comment. However, the new Comment not saved by the rails - the error does not return, rather the Dish object is returned. However, I see Unpermitted parameters: :id, :created_at in the rails s console. How to get rails to save a new comment?

The page ( dishes/9 ), from where I add a comment to the dish, looks lower on the Angular client side. enter image description here

Rails Server Logs

On the side of the rails below is what I see in params - I see a new comment - {"author"=>"JANE7777", "rating"=>3, "comment"=>"COMMENT7777", "date"=>"2017-11-12T12:58:12.555Z"} there.

 Started PUT "/dishes/9" for 127.0.0.1 at 2017-11-12 18:28:12 +0530 Processing by DishesController#update as HTML Parameters: {"id"=>"9", "name"=>"Uthappizza", "image"=>"images/uthappizza.png", "category"=>"mains", "label"=>"Hot", "price"=>"4.99", "featured"=>true, "description"=>"A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.", "created_at"=>"2017-11-01T04:30:09.407Z", "comments"=>[{"id"=>46, "rating"=>5, "comment"=>"Imagine all the eatables, living in conFusion!", "author"=>"John Lemon", "date"=>"2012-10-16T17:57:28.556Z"}, {"id"=>47, "rating"=>4, "comment"=>"Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", "author"=>"Paul McVites", "date"=>"2014-09-05T17:57:28.556Z"}, {"id"=>48, "rating"=>3, "comment"=>"Eat it, just eat it!", "author"=>"Michael Jaikishan", "date"=>"2015-02-13T17:57:28.556Z"}, {"id"=>49, "rating"=>4, "comment"=>"Ultimate, Reaching for the stars!", "author"=>"Ringo Starry", "date"=>"2013-12-02T17:57:28.556Z"}, {"id"=>50, "rating"=>2, "comment"=>"It your birthday, we're gonna party!", "author"=>"25 Cent", "date"=>"2011-12-02T17:57:28.556Z"}, {"id"=>51, "rating"=>4, "comment"=>"great dish", "author"=>"Jogesh", "date"=>"2017-10-30T05:03:39.656Z"}, {"author"=>"JANE7777", "rating"=>3, "comment"=>"COMMENT7777", "date"=>"2017-11-12T12:58:12.555Z"}], "dish"=>{"id"=>"9", "name"=>"Uthappizza", "image"=>"images/uthappizza.png", "category"=>"mains", "label"=>"Hot", "price"=>"4.99", "featured"=>true, "description"=>"A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.", "created_at"=>"2017-11-01T04:30:09.407Z"}} Dish Load (1.0ms) SELECT "dishes".* FROM "dishes" WHERE "dishes"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] [25, 34] in C:/apps/railsApi/app/controllers/dishes_controller.rb 25: end 26: 27: # PATCH/PUT /dishes/1 28: def update 29: byebug => 30: if @dish.update(dish_params) 31: render json: @dish 32: else 33: render json: @dish.errors, status: :unprocessable_entity 34: end (byebug) params <ActionController::Parameters {"id"=>"9", "name"=>"Uthappizza", "image"=>"images/uthappizza.png", "category"=>"mains", "label"=>"Hot", "price"=>"4.99", "featured"=>true, "description"=>"A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.", "created_at"=>"2017-11-01T04:30:09.407Z", "comments"=>[{"id"=>46, "rating"=>5, "comment"=>"Imagine all the eatables, living in conFusion!", "author"=>"John Lemon", "date"=>"2012-10-16T17:57:28.556Z"}, {"id"=>47, "rating"=>4, "comment"=>"Sends anyone to heaven, I wish I could get my mother-in-law to eat it!", "author"=>"Paul McVites", "date"=>"2014-09-05T17:57:28.556Z"}, {"id"=>48, "rating"=>3, "comment"=>"Eat it, just eat it!", "author"=>"Michael Jaikishan", "date"=>"2015-02-13T17:57:28.556Z"}, {"id"=>49, "rating"=>4, "comment"=>"Ultimate, Reaching for the stars!", "author"=>"Ringo Starry", "date"=>"2013-12-02T17:57:28.556Z"}, {"id"=>50, "rating"=>2, "comment"=>"It your birthday, we're gonna party!", "author"=>"25 Cent", "date"=>"2011-12-02T17:57:28.556Z"}, {"id"=>51, "rating"=>4, "comment"=>"great dish", "author"=>"Jogesh", "date"=>"2017-10-30T05:03:39.656Z"}, {"author"=>"JANE7777", "rating"=>3, "comment"=>"COMMENT7777", "date"=>"2017-11-12T12:58:12.555Z"}], "controller"=>"dishes", "action"=>"update", "dish"=>{"id"=>9, "name"=>"Uthappizza", "image"=>"images/uthappizza.png", "category"=>"mains", "label"=>"Hot", "price"=>"4.99", "featured"=>true, "description"=>"A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.", "created_at"=>"2017-11-01T04:30:09.407Z"}} permitted: false> (byebug) c Unpermitted parameters: :id, :created_at (0.0ms) BEGIN (0.0ms) COMMIT [active_model_serializers] Comment Load (0.0ms) SELECT "comments".* FROM "comments" WHERE "comments"."dish_id" = $1 [["dish_id", 9]] [active_model_serializers] Rendered DishSerializer with ActiveModelSerializers::Adapter::Attributes (31.29ms) Completed 200 OK in 1901725ms (Views: 37.5ms | ActiveRecord: 5.0ms) 

Client models

The Dish model has Comment[] as one of its members. When a new comment is added through the form, Comment clicks on the dish.comments array before submitting the Dish object to the Rails API.

Comment client-side model

 export class Comment { rating: number; comment: string; author: string; date: string; } 

Post client-side model

 import { Comment } from './comment'; export class Dish { id: number; name: string; image: string; category: string; label: string; price: string; featured: boolean; description: string; comments: Comment[]; } 
+7
ruby-on-rails angular
source share
1 answer

Id recommends using a comment controller and forming a nested RESTful route.

First, submit a request, including dish_id in / comments. Youre trying to create a comment rather than updating the Dish.

Secondly, form a nested route: / dishes /: dish_id / comments

Here's how to do it: http://guides.rubyonrails.org/routing.html#nested-resources

The reason for your error is that you violated the expected parameter structure. For PUT, your parameters should be:

 { id: <record to update>, dish: { name: "blah", comments: [{...},{...}] } } 

Again, I really recommend you Dont PUT to Dish if you just want to add a comment. For example: the above would be desirable to replace all the comments on the dish! If you are creating a record, create this record, do not update its parent.

If you want to update the Dish when adding a new comment, you can add a comment model callback to create or do so in the action of the comment controller controller.

0
source share

All Articles