I am looking to modify various attributes linked to Rails

My Desire for Reality

I am looking to update multiple related values in Rails by sending an update request from JavaScript. While creating data was seamless, I encountered difficulties when attempting to update it.

#Code

JavaScript*

export const actions = {
  // Posting the selected book
  post (context) {
    const list = context.state.todos.list
    const selectedBook = context.state.book.selectedBook

    // Mapping out array
    const postItemsAttributes =
      list.map((item) => {
        return {
          content: item.content,
          status: item.status
        }
      })

    // plugin/bookInfo  $title,$author,$image
    this.$axios.$post(url.POST_API + 'posts', {
      post: {
        title: this.$title(selectedBook),
        author: this.$author(selectedBook),
        image: this.$image(selectedBook),
        post_items_attributes: postItemsAttributes
      }
    })
      .then((responseBook) => {
        context.commit('book/userBook', responseBook)
        context.commit('book/clearBook')
        context.commit('todos/clear')
      })
  },

//////////////////////////////////////////////////////////////////////////////////

// Issue with updating values
  update (context) {
    const list = context.state.todos.list
    const bookId = context.state.book.selectedBook.id
    const content =
    list.map((item) => {
      return {
        content: item.content,
        status: false
      }
    })
    this.$axios.$patch(url.POST_API + 'posts/' + bookId, {
      post: {
        post_items_attributes: content
      }
    })
  }

//////////////////////////////////////////////////////////////////////////////////

}

Rails controller


class Api::V1::PostsController < ApplicationController

    def create
        posts = Post.new(post_params)
        if posts.save
            render json: "OK", status: 200
        else
            render json: "EEEOR", status: 500
        end
    end

     def update
        post = Post.find(params[:id])
        post.post_items.update(content_params)
     end
     


        private
              # update
            def content_params
                params.require(:post).permit(post_items_attributes:[:id, :content, :status])
            end
            #create
         def post_params
                params.require(:post).permit(:title, :author, :image, post_items_attributes: [:id, :content, :status])
         end
end

model/post

class Post < ApplicationRecord
    has_many :post_items, dependent: :destroy
    accepts_nested_attributes_for :post_items, allow_destroy: true

    validates :title, presence: true
    validates :author, presence: true
    validates :image, presence: true
end

model/post_item

class PostItem < ApplicationRecord
belongs_to :post

end

Error

api_1    | Started PATCH "/api/v1/posts/16" for 172.29.0.1 at 2021-09-06 22:15:10 +0900
api_1    | Processing by Api::V1::PostsController#update as HTML
api_1    |   Parameters: {"post"=>{"post_items_attributes"=>[{"content"=>"Test", "status"=>false}]}, "id"=>"16"}
api_1    |   Post Load (13.0ms)  SELECT "posts".* FROM "posts" WHERE "posts"."id" = $1 LIMIT $2  [["id", 16], ["LIMIT", 1]]
api_1    |   ↳ app/controllers/api/v1/posts_controller.rb:23:in `update'
api_1    |   PostItem Load (15.4ms)  SELECT "post_items".* FROM "post_items" WHERE "post_items"."post_id" = $1  [["post_id", 16]]
api_1    |   ↳ app/controllers/api/v1/posts_controller.rb:24:in `update'
api_1    | Completed 204 No Content in 49ms (ActiveRecord: 29.5ms | Allocations: 1576)

What I attempted on my own

① I tried using post_all, but it didn't work because post_all is used directly in the model.

Answer №1

The main purpose of using nested attributes is to facilitate updating child elements through the parent element:

module Api 
  module V1
    class PostsController < ApplicationController

      # POST /api/v1/posts
      def create
        post = Post.new(create_params)
        if post.save
          render json: post, status: :created,
          location: [:api, :v1, post]
        else
          render json: { errors: post.errors.full_messages },
          status: :unprocessable_entity # not 500 - Internal Server Error!
        end
      end

      # PATCH /api/v1/posts/1
      def update
        if post.update(update_params)
          head :ok 
          # you can also return the updated record
          # this is useful if you have any server side transformations 
          # to the record 
          # render json: post, status: :ok
        else
          render json: { errors: post.errors.full_messages },
          status: :unprocessable_entity 
        end
      end
      
      private
      # just a memoizing convenience method to keep it DRY
      def post 
        @post ||= Post.find(params[:id])
      end 
      
      # use different parameter whitelists for updating and creating 
      # without needing comments to explain them 
      def update_params
        params.require(:post)
        .permit(
          post_items_attributes: post_item_params
        )
      end

      def create_params
        params.require(:post)
        .permit(
          :title, :author, :image, 
          post_items_attributes: post_item_params
        )
      end
      
      def post_item_params
        [:id, :content, :status]
      end
    end
  end 
end 

It's important to avoid using render json: "OK", as it is considered an anti-pattern. Provide meaningful JSON responses that the client can utilize or simply return headers. Utilize appropriate HTTP status codes to communicate the success or failure of operations to the client.

If you need to update a specific post item separately, consider implementing a distinct PATCH /api/v1/post_items/:id route.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why would you need multiple root handlers?

One interesting feature to note is that multiple callback functions can be used as middleware to handle a request. These callbacks can take on different forms - they could be in the form of a single function, an array of functions, or even a combination of ...

What will be provided as the outcome?

I have recently started learning express.js. The following code snippet is taken from the router library of express.js. var proto = module.exports = function(options) { options = options || {}; function router(req, res, next) { router.handle(req, ...

What is the best way to incorporate the skrollr-body tag without altering the overall height of the

Skrollr has been a game-changer, so thank you to the geniuses behind it. I made sure to properly place the skrollr-body tag around all elements except for the fixed background in order to make it work on mobile. However, I'm noticing that it is cutti ...

Infusing JavaScript with vibrant images

I am currently facing an issue where I am trying to insert images with JavaScript attached to them. Oddly enough, it seems to work fine on Firefox but the images or icons do not display on Internet Explorer. This is how I have written the code: <a hre ...

Finding a specific object within an array of objects by searching through a key value pair

In my collection, I have an array of objects structured as follows: [{ "businessunit": [{ "Area": [{ "Asset": [{ "Wells": { "Well": "Well 11" }, "name": "Field ...

Searching for "unique elements" using AngularJS ng-repeat

I am trying to organize a list by category, but the challenge is that each category input is customized and can be added by any user in the list. My initial attempt involved using ng-repeat to filter out duplicate values (as seen in the code snippet uniqu ...

The Vue component fails to display the updated data even after the prop data has been modified

This is the parent component called abc.vue <v-card outlined class="mt-4"> <DetailsTable v-show="toggleClientData" :columnDefs="columnDefs" :rowData="rowData" /> </v-card> methods:{ aggridData() { let self = this; th ...

Assign a variable to the result of ajax that remains unchanged until it is specifically invoked

I am currently working on the final part of my radio script, specifically focusing on the "last song" section. My goal is to retrieve a URL from an external PHP script, play the song, and once the song ends, I want to set a global variable equal to the cur ...

What is the best way to retrieve an element from an array within a script?

As a newbie in the realm of vue and Laravel Framework, I am eager to fetch data from an API and display it dynamically on my web page. To achieve this, I have already set up a table named 'Progress' where I seeded some initial data. Utilizing AP ...

Freeze your browser with an Ajax request to a specific URL

There is a function in my view that transfers a value from a text box to a table on the page. This function updates the URL and calls another function called update_verified_phone(). The update_verified_phone() function uses a model called user_info_model( ...

Four unique chip/tag colors, personalized to suit your style

Currently, I have integrated two arrays into my autocomplete menu where the chip/tag color is either primary or secondary based on the array the selected component belongs to. I aim to include all four arrays in the menu (top10Songs, top10Artists, top10Fi ...

How can I prevent my Vue.js application from losing focus when navigating to different components?

I am encountering an issue with my Vue.js app where the focus is lost when changing routes. Initially, when the site loads, the first element of the header component is correctly in focus as desired. However, when navigating to a different link on the site ...

Create a row in React JS that includes both a selection option and a button without using any CSS

My dilemma involves a basic form consisting of a select element and a button. What I want to accomplish is shifting the position of the form to the right directly after the select element Below is the code snippet that I have: return ( <> <div ...

Loading jQuery on an ajax request

The loader is working with the code now, but it is not replacing and calling the URL. The ajax url call should be placed within searchable. <button onclick="myFunction()">LOAD</button><br /><br /> <div class="spinner bar hide" ...

The error message "TypeError: self.parent.parent.context.parseInt is not a function" indicates that

My goal is to set the height of an image using ngStyle by calculating it with a Math operation in the following way: <div [ngSwitch]="tbNm?tbNm:'itm0'"> <ion-list *ngFor="let vl of scrnshot;let ind=index"> <img *ngSwitch ...

I desire to incorporate a subtle fading effect into the script

I have written the script code and now I am looking to add a fade effect to it. Can anyone guide me on how to achieve this? Your help is much appreciated! ※I used an online translator as English is not my native language. Please bear with any awkward ph ...

Tips for displaying a refresh indicator while making an ajax call for refreshing data:

I have successfully implemented jQuery code that refreshes a specific div every 10 seconds without reloading the entire page. However, during this refresh process, the user does not visually perceive any changes happening in the browser. While there are n ...

Displaying a group of elements in ReactJS

I'm currently working on assembling an array using different JSX components. There's a function I've created that populates this array with components and then returns it. let components = []; switch (obj.type) { case 'title': ...

Creating an asynchronous function using EventEmitter

I am new to node.js and I'm trying to take advantage of asynchronous and event-driven behavior in my code. I used to think that in node, anything involving an Event object would result in asynchronous execution. So I decided to test this theory with ...

Tracking the referral source when the email box is clicked

document.referrer is a JavaScript method that returns the URI of the page that linked to the current page. If the user navigated directly to the page, for example through a bookmark, the value returned by document.referrer will be an empty string. You can ...