i am doing my first project and i need your help. I am using act_as_shopping_cart gem, and user model like in Rails Tutorial. How can i bind user and shopping cart? I tried bound shopping_cart.id and user.id, but without succes, still all users have same cart. It my code: Shopping cart controller:
class ShoppingCartsController < ApplicationController
before_filter :extract_shopping_cart
def create
@product = Sketchbook.find(params[:product_id])
@shopping_cart.add(@product, @product.price)
redirect_to shop_path
end
def show
end
private
def extract_shopping_cart
shopping_cart_id = session[:shopping_cart_id]
@shopping_cart = session[:shopping_cart_id] ? ShoppingCart.find(shopping_cart_id) : ShoppingCart.create
session[:shopping_cart_id] = @shopping_cart.id
end
end
User controller:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:show, :edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to user_url(@user)
flash[:notice] = "Użytkownik stworzony"
else
render 'new'
end
end
def edit
end
def update
if @user.update_attributes(user_params)
redirect_to user_url(current_user)
flash[:notice] = "Dane zaktualizowane"
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "Konto usunięte"
redirect_to root_url
end
private
def user_params
params.require(:user).permit(:username, :name, :surname, :email, :adress, :city, :zip_code, :country, :password, :password_confirmation)
end
#confirms a logged user
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Zaloguj się"
redirect_to login_url
end
end
#confirms the correct user
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
Session helper:
module SessionsHelper
#log in method
def log_in(user)
session[:user_id] = user.id
end
#remember a user in a presisnet session
def remember(user)
user.remember
cookies.permanent.signed[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
#returns true if the given user i current user
def current_user?(user)
user == current_user
end
#forgets a presistent session
def forget(user)
user.forget
cookies.delete(:user_id)
cookies.delete(:remember_token)
end
# returns logged user
def current_user
if (user_id = session[:user_id]) #open broweser
@current_user ||= User.find_by(id: session[:user_id])
elsif (user_id = cookies.signed[:user_id]) #cookie is present
user= User.find_by(id: cookies.signed[:user_id])
if user && user.authenticated?(cookies[:remember_token])
log_in user
@current_user = user
end
end
end
# Returns true if the user is logged in
def logged_in?
!current_user.nil?
end
# logs out current user
def log_out
forget(current_user)
session.delete(:user_id)
@current_user = nil?
end
#stores the url trying to be accessed
def store_location
session[:forwarding_url] = request.url if request.get?
end
#redirect back to stored location (or to the default)
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
end
I'd also happy if you could give me some other guidances how to improve this code.
Rails lets you do lots of "magic" where code in one place magically affects behavior elsewhere in the app, with no explicit connection between the two. This is really powerful but I think is also a huge problem for beginning developers; when you're learning Rails, it's super hard to keep track of how one thing is related to another so having those connections hidden up in the inheritance chains is almost cruel.
So if you're in a place where the Rails magic is overwhelming (it certainly still is for me), my advice is to write stupid code that makes connections as local and simple as possible. Sometimes it's worth doing that even when it deviates from "the Rails way"; would you rather have "proper Rails" code, or code that's easy to understand and easy to maintain?
Anyway, your specific problem might relate to the session. In ShoppingCartsController
you're defining @shopping_cart
by looking up a session[:shopping_cart_id]
. If multiple users (after logging out and logging in as someone else) are ending up with the same @shopping_cart.id
, that must mean that their session values are the same. In the beginning of the relevant controller action, add a puts
statement to give you extra info (it spits out to the console) about what the session values are:
puts session
If multiple users have the same session values, it likely means that the session isn't getting cleared properly when you log out and log in as someone else. You could test that by setting a different session variable, and seeing if that also persists from one user to another.
In general, adding lots of puts
statements at the beginning of all relevant controller actions is a great (and super simple) way to get insight into what your application is thinking.
Hope that helps!