Reputation: 405
Now I have three models: Product, Cart, CartItem. Here's the related methods and associations:
cart.rb
class Cart < ApplicationRecord
has_many :cart_items
has_many :products, :through => :cart_items, :source => :product
cart_item.rb (it has 2 related integer columns, :product_id
& :cart_id
)
class CartItem < ApplicationRecord
belongs_to :cart
belongs_to :product
application_controller.rb
class ApplicationController < ActionController::Base
helper_method :current_cart
def current_cart
@current_cart ||= find_cart
end
private
def find_cart
cart = Cart.find_by(id: session[:cart_id])
if cart.blank?
cart = Cart.create
end
session[:cart_id] = cart.id
return cart
end
end
In carts_controller.rb I defined a method to delete specific cart_item in carts#index page:
class CartsController < ApplicationController
def destroy_one
@cart_item = current_cart.cart_items.find_by_product_id(params[:id])
@product = @cart_item.product
@cart_item.destroy
redirect_to :back
In the first line of destroy_one method, I can use find_by_product_id(params[:id])
to get the right cart_item
Then I tried find_by(product_id: params[:id])
, it works too.
But if I use find_by(params[:product_id])
,something went wrong. When I click delete button, it won't raise an exception, but it will delete another cart_item. It seems rails randomly picked a cart_item and delete it.
Obviously, find_by(params[:product_id])
worked incorrectly here.
My question is:
In this case, I confused with how rails find the right object step by step ? In one Cart, there's many cart_items and products, its reasonable to locate a cart_item by using :product_id
. But what's the difference between :
find_by_product_id(params[:id])
vs find_by(params[:product_id])
Respectively, how they work?
Upvotes: 0
Views: 81
Reputation: 5482
The problem is that you're using find_by(params[:product_id])
wrong. You have to pass the key you want to search for explicitly like so:
find_by(product_id: params[:product_id])
User.find_by(id: 1)
-> User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Respectively you can use it as you stated already:
find_by_product_id(params[:product_id])
User.find_by_id(1)
-> User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
As you can see, both approaches generate the very same SQL query.
Upvotes: 1