【问题标题】:Conventional way of decrementing an attribute, which action to use?减少属性的常规方法,使用哪个操作?
【发布时间】:2015-01-19 23:05:15
【问题描述】:

如果我想减少一个对象的计数器属性,是添加到update动作,还是destroy动作,还是创建一个新动作更好?强>

为了更好地解释,假设您有一个 Product 和一个 CartItem 类,并且每次用户将相同的产品添加到她的购物车时,而不是拥有相同 CartItem 对象的两个副本,您递增CartItemamount 属性。

如果我想让用户减少金额,我应该使用什么?例如,类似下面的代码是一种可行且传统的方法吗?还是创建一个新动作更好?

查看:

...
<%= button_to 'Remove One', [cart_item, remove_one: true], method: :patch %>
...

控制器:

def update
  if params[:remove_one]
    if @cart_item.quantity > 1
      @cart_item.decrement!(:quantity)
      flash[:notice] = "Removed one of #{@cart_item.product.title}"
      redirect_to :back
    else
      destroy
    end
  end

  return
end

注意:我知道标题听起来有点误导,但我并不是在寻找一种方法来减少 Rails 中的属性。我想知道的是,如果你有这样的需求,你会放在哪个动作中? 你如何决定什么动作?

编辑:伙计们,我真的期待一些可信的东西,比如来自维护良好的源代码的示例、高评价的书籍等。在这种情况下,不幸的是我无法做到将赏金奖励给任何人。

【问题讨论】:

    标签: ruby-on-rails rest restful-architecture convention


    【解决方案1】:

    我认为没有 100% 正确的答案,但根据我的经验,我看到两个选项比您的代码示例更好:

    1. 在控制器上执行减量操作,并在控制器中使用 decrement_counter 方法 (doc)。如果您在同一模型上同时进行更新,这会有所帮助(尽管购物车通常不会出现这种情况)。

    2. 有一个更新方法并在视图中渲染一个小表单:

    景色

    <%= form_for cart_item do |form| %>
     <%= form.hidden_field :quantity, cart_item.quantity-1 %>
     <%= form.submit 'Remove One'
    <% end %>
    

    在控制器中

    def update
      @cart_item.update(cart_item_params)
      @cart_item.destroy if @cart_item.quantity == 0
      #in the above 
      redirect_to :back
    end
    
    def cart_item_params
      params.require(:cart_item).permit(:quantity)
    end
    

    【讨论】:

    • 感谢您的回答。您提供的第一个选项与为此目的使用哪个操作无关。而且我认为您提供的第二个选项不是这样做的好方法。例如,假设用户计算机上打开了两个浏览器,她有 4 个相同的项目。如果用户单击“删除”按钮,她将拥有 3 个项目。但是,如果她在另一个浏览器窗口中再次单击“删除”按钮,则不会发生任何事情。因为另一个窗口也显示“将数量更改为 3”。所以我认为这不是更好的方法。
    • 那么我推荐第一个选项。有一条类似PATCH /cart/items/:cat_item_id/decrement 的路线,并在需要时执行 decrement_counter 并销毁。对于第二个选项,您可以传递 quantity_delta 参数并使用 cart_item.update(quantity: cart_item.quantity+params[:quantity_delta] 进行更新。
    【解决方案2】:

    CartItem类中添加专用方法...如

    ##it will return either true or false
    def !!update_amount
        ###use if condition if you need  
        if self.quantity > 1
          self.update_attribute :amount,self.amount+=amount-1 
        end
    end
    

    在任何你想要的地方使用它,例如:--

    def update
      if params[:remove_one]
       ##call the method to get only true or false
        if @cart_item.update_amount
          flash[:notice] = "Removed one of #{@cart_item.product.title}"
          redirect_to :back
        else
          destroy
        end
      end
    
      return
    end
    

    【讨论】:

      【解决方案3】:

      对我来说,将它放在一个单独的方法中在语义上是有意义的。

      您正在更新模型上的属性,这意味着您应该使用PATCH 方法,并且最好按照rails 的约定调用update 方法,所以在我看来,这个单独的方法调用应该在不改变的情况下执行RESTful 路由。

      before_action :inventory_check, only: :update
      
      def update
        if @cart_item.update
          flash[:notice] = "Updated your cart."
        else
          flash[:error] = "Couldn't update your cart."
        end
        redirect_to :back
      end
      
      def destroy
        @cart_item.destroy
        flash[:notice] = "Item removed from your cart."
        redirect_to :back
      end
      
      private
      
      def inventory_check
        if params[:decrement] && @cart_item.quantity == 1
          redirect_to :destroy
        end
      end
      

      【讨论】:

        【解决方案4】:

        在我看来,您的CartItem 对象描述了ProductCard 之间的多对多关系。因此,当您将Product 添加到Cart 时,您只是在更新(或创建如果还没有)该特定Production-Cart 关系的内容。

        从这个意义上说,我建议您将减量放在update 方法中。但是,如果您想做更多的逻辑来确定这种关系是否存在,您也可以创建一个新方法并在其中进行所有验证。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-08-27
          • 2019-06-15
          • 2022-01-24
          • 1970-01-01
          • 2013-04-23
          • 2012-08-09
          • 2018-06-15
          相关资源
          最近更新 更多