简体   繁体   中英

Rails route to update an associated model's attributes

I have a Cart , CartProduct , and Product model. Whenever a product is added to the cart, the CartProduct model, which represents the items in the shopping cart, has an attribute quantity that's updated accordingly. Currently I'm sending PATCH requests on Cart to update the Cart s associated CartProduct models.

My question is: when I want to update a shopping cart item, would it be better to have add_product , remove_product , etc. methods in the CartProduct model, or should I have those methods in the Cart model (my current setup below, which functions just fine)? Or is this up to personal preference?

Please note that the code is incomplete; I just picked out the important parts for this question:

class Cart < ActiveRecord::Base
    has_many :cart_products, inverse_of: :cart, dependent: :destroy
    has_many :products, through: :cart_products, source: :product

    def add_product(product_id) #directed here from PATCH request
      #pulls the associated cart_product for this cart and updates  
    end

    def remove_product(product_id) #directed here from PATCH request
    end
end

class CartProduct < ActiveRecord::Base
    belongs_to :cart, inverse_of: :cart_products
    belongs_to :product, inverse_of: :cart_products

    #or should add_product, remove_product methods go here instead?
end

class Product < ActiveRecord::Base
    has_many :cart_products, inverse_of: :product, dependent: :destroy
    has_many :carts, through: :cart_products, source: :cart
end

When a user increments the quantity of a shopping cart item, what's actually being updated is the CartProduct model, not the Cart model - so this worries me because I'm sending a PATCH request on the Cart , while I suppose it would make more sense to have a route/method on the CartProduct model because that's the actual model being updated.

I think what you're asking would be left up to personal preference.

My preference would be to keep it exactly as you have it and call add_product from your Cart model.

Others may suggest creating a completely new class, observer, etc to handle that relationship between the two models but what you end up doing is making one class that is dependent upon two models rather than keeping what you have and just having one models method dependent on one other model's attribute.

You mixing up what controllers and models do in MVC.

Models are how you implement the business logic in your application, and how the different objects are tied together. Models should not know anything about PUT, POST, PATCH or even that there is a current request, its not their job.

So if you are creating a method in your model to handle a specific kind of request than your doing it wrong.

Controllers are responsible for responding to requests. Together with routes they build the RESTful interface that your app exposes.

Exactly how to deal with nested resources like in this case is a matter of opinion.

I'm going to use the more common term line item instead of CartProduct for clarity:

         Prefix Verb   URI Pattern                          Controller#Action
       products GET    /products(.:format)                  products#index
                POST   /products(.:format)                  products#create
        product GET    /products/:id(.:format)              products#show
                PATCH  /products/:id(.:format)              products#update
                PUT    /products/:id(.:format)              products#update
                DELETE /products/:id(.:format)              products#destroy
cart_line_items GET    /carts/:cart_id/line_items(.:format) line_items#index
                POST   /carts/:cart_id/line_items(.:format) line_items#create
      line_item GET    /line_items/:id(.:format)            line_items#show
                PATCH  /line_items/:id(.:format)            line_items#update
                PUT    /line_items/:id(.:format)            line_items#update
                DELETE /line_items/:id(.:format)            line_items#destroy
          carts GET    /carts(.:format)                     carts#index
                POST   /carts(.:format)                     carts#create
           cart GET    /carts/:id(.:format)                 carts#show
                PATCH  /carts/:id(.:format)                 carts#update
                PUT    /carts/:id(.:format)                 carts#update
                DELETE /carts/:id(.:format)                 carts#destroy

In many cases using nested attributes and creating/updating/deleting child records is a good solution - but it often leads to the temptation of creating a very limited set up of actions that do everything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM