This is the first time I''m developing a site with rails (online shop) and I really would like to ask for help with authetication. I''ve installed acts_as_autheticated and I set up that certain pages can only be viewed if the user logs in (for example editing or adding new products). I am just trying to get my head around certain roles for certain users. How should I go around creating different roles for different users? what if I want to make it mandatory for customers to log in in order to complete a transaction? I also discovered RoleRequirement yesterday on Google code. Should I use this plugin? Would anyone know any good tutorail to teach me how to accomplish this? Please help. Elle --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
The trick I did was to add flags to the user table, which is what acts_as_authenticated is pointed at in my case. These flags: superadmin, a boolean, defaults to false forumadmin, a boolean, defaults to false banned, a boolean, defaults to false I modified lib/authenticated_system.rb to teach it that I ALWAYS want a current_user, and that it can never be nil. I can send you some diffs if you want. The purpose in this is so I can write code that reads like: current_user.superadmin? without having to write: if !current_user.nil? && current_user.superadmin? --Michael On 10/11/07, elle <waznelle-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > This is the first time I''m developing a site with rails (online shop) > and I really would like to ask for help with authetication. > > I''ve installed acts_as_autheticated and I set up that certain pages > can only be viewed if the user logs in (for example editing or adding > new products). I am just trying to get my head around certain roles > for certain users. > How should I go around creating different roles for different users? > what if I want to make it mandatory for customers to log in in order > to complete a transaction? > > I also discovered RoleRequirement yesterday on Google code. Should I > use this plugin? > Would anyone know any good tutorail to teach me how to accomplish > this? > > Please help. > > Elle > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks Michael. Would appreciate anything you can send me about this. This might seem like a really silly question: Do I use the same users model for both admins and cutomers? Because the way, my logic works is to create another table of customers and have it under admin control. My logic also says that I will have the following relationships: Customer has many orders Order belongs to one customer But then, can I use the same acts_as_authenticated to get the cutomers to login? And how do I do this? And am I missing something with my relationships? Many questions, I know :-/ Thanks, Elle On Oct 12, 4:07 pm, "Michael Graff" <skan.gryp...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> The trick I did was to add flags to the user table, which is what > acts_as_authenticated is pointed at in my case. > > These flags: > > superadmin, a boolean, defaults to false > forumadmin, a boolean, defaults to false > banned, a boolean, defaults to false > > I modified lib/authenticated_system.rb to teach it that I ALWAYS want > a current_user, and that it can never be nil. I can send you some > diffs if you want. The purpose in this is so I can write code that > reads like: > > current_user.superadmin? > > without having to write: > > if !current_user.nil? && current_user.superadmin? > > --Michael > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
randomutterings-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2007-Oct-12 14:47 UTC
Re: Authentication Help
I took the approach of using roles and rights. A user has and belongs to many roles and a role has many rights. A right would be to a specific action on a specific controller. Then just use a before filter in your application.rb to check if the user has a role that has the right to access the action in the controller he is trying to access. It sounds more complicated than it is but it works great and its very flexible. Here is some code to get you started if you''re interested in doing it this way. role.rb ---------------------------- class Role < ActiveRecord::Base has_and_belongs_to_many :users has_and_belongs_to_many :rights validates_uniqueness_of :name def has_right_for?(action_name, controller_name) rights.detect{ |right| right.has_right_for?(action_name, controller_name) } end end ----------------------------- right.rb ----------------------------- class Right < ActiveRecord::Base has_and_belongs_to_many :roles def has_right_for?(action_name, controller_name) action == action_name && controller == controller_name end end _________________ user.rb ------------------------------ class User < ActiveRecord::Base has_and_belongs_to_many :roles def has_right_for?(action_name, controller_name) roles.detect{ |role| role.has_right_for?(action_name, controller_name) } end end ------------------------------- application.rb ------------------------------- class ApplicationController < ActionController::Base before_filter :check_authorization def check_authorization if session[:user].blank? flash[:error] = "You must login to view the page you requested" redirect_to :action => "login", :controller => "user" return false end # logged in users can view the following pages with out an explicit right unless action_name == "logout" || action_name =~ %r{my_} unless has_right?(action_name, self.class.controller_path) flash[:error] = "You are not authorized to view the page you requested" redirect_to :action => "index", :controller => "home" return false end end end def has_right?(action_name, controller_name) unless session[:user].blank? user = User.find(session[:user]) user.has_right_for?(action_name, controller_name) end end end ---------------------------------- Just use skip_before_filter on any actions you want open to users who are not logged in (don''t forget to do this on the login page!) On Oct 12, 1:52 am, elle <wazne...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Thanks Michael. Would appreciate anything you can send me about this. > > This might seem like a really silly question: > Do I use the same users model for both admins and cutomers? > Because the way, my logic works is to create another table of > customers and have it under admin control. > My logic also says that I will have the following relationships: > Customer has many orders > Order belongs to one customer > > But then, can I use the same acts_as_authenticated to get the cutomers > to login? > And how do I do this? > And am I missing something with my relationships? > > Many questions, I know :-/ > > Thanks, > Elle > > On Oct 12, 4:07 pm, "Michael Graff" <skan.gryp...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > The trick I did was to add flags to the user table, which is what > > acts_as_authenticated is pointed at in my case. > > > These flags: > > > superadmin, a boolean, defaults to false > > forumadmin, a boolean, defaults to false > > banned, a boolean, defaults to false > > > I modified lib/authenticated_system.rb to teach it that I ALWAYS want > > a current_user, and that it can never be nil. I can send you some > > diffs if you want. The purpose in this is so I can write code that > > reads like: > > > current_user.superadmin? > > > without having to write: > > > if !current_user.nil? && current_user.superadmin? > > > --Michael--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Oct 13, 1:47 am, "randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org" <randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I took the approach of using roles and rights. A user has and belongs > to many roles and a role has many rights. A right would be to a > specific action on a specific controller. Then just use a before > filter in your application.rb to check if the user has a role that has > the right to access the action in the controller he is trying to > access. It sounds more complicated than it is but it works great and > its very flexible. Here is some code to get you started if you''re > interested in doing it this way.Thanks Michael. I really wanted to have a separate model for Customer (bacause I have about 3 admins, 4 staff and 150 customers). I also wanted to have a relationship between customers and orders (to show orders per customer). But i''ve spend all yesterday and today on it and I just don''t know how to implement it. Any advice, before I give in and just use one User model for everyone? Elle --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
In nearly all my applications, I do something far more complicated. But to answer your question, I use one table for "things that can log in" and have a default-false "is admin" flag. I want to write the roles/permissions model thing, and intend to do it eventually, so if you can that''s the most flexible but most complicated to get started on method. No matter what you choose, I would suggest having an is_admin? method that you can use in your checks. Then should you change your method from a simple flag to a full-blown roles/rights system, you don''t have to change as much code. The more complicated thing I do is this: Since most users eventually report a problem, I have a way for an admin to set themselves up as an "effective user" -- that is, they can become that user for all purposes, and see exactly what the user would see. The only difference is they cannot complete certain operations without a small dialog box saying something like: "You are in administrative mode, and are making this change as user <username>. Do you really want to do this?" --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Oct 14, 2007, at 12:45 , Michael Graff wrote:> The more complicated thing I do is this: Since most users eventually > report a problem, I have a way for an admin to set themselves up as an > "effective user" -- that is, they can become that user for all > purposes, and see exactly what the user would see.This is on my list of features to implement on a current project. I haven''t yet done any research for how others have done this (which I intend to do when I get to that feature), but since you brought it up I was wondering if you''d care to share how you did this. Michael Glaesemann grzm seespotcode net --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I ended up with the following: 1) For admin pages: I used acts_as_authenticated plugin for users (and by users I mean admins). My aaplication.rb controller has: class ApplicationController < ActionController::Base include AuthenticatedSystem ... My base_controller.rb for the admin area inherits from the ApplicationController and also has a before_filter: class Admin::BaseController < ApplicationController before_filter :login_required end And all my admin pages inherit from the base controller by using: class Admin::UserController < Admin::BaseController ... Which means, they all require login to be viewed. In my views/layout/application.rhtml I have: <p id="adminlogin"> <% if logged_in? %> Logged in as <%= current_user.login %> (<%= link_to "Logout", :controller => "/admin", :action => "logout" %>) <% else %> <%= link_to "Admin Login", :controller => "/admin", :action => "login" %> <% end %> </p> 2) Next, I added another column in my users table called ''role'' (:integer, :limit => 1) to identify 1 for manager and 0 for staff. Only managers can add admins. Staff can do everything else in the admin area besides administering admins. So, in my user_controller.rb I added another before_filter: before_filter :check_authorization def check_authorization user = User.find(session[:user]) unless user.role? flash[:notice] = "You are not authorized to view the page requested" redirect_to :controller => ''product'', :action => ''index'' return false end end 3) Lastly, I created a customer model which admins can create, edit.... Now, only logged customers can checkout. So, in my checkout controller I added all my customer''s login methods, like so: class CheckoutController < ApplicationController before_filter :initialize_cart before_filter :authorize, :except => ["login"] def authorize return true if @c flash[:notice] = "To place your order please login" redirect_to :controller => "catalog" end def login # examine the form data for "name" and "password" pw,name = params[:customer].values_at(*%w{password name}) # Retrieve the customer record for the name and store it in a variable ''c'' c = Customer.find_by_name(name) # if such record exists, and it''s password matches the password from the form if c && Digest::SHA1.hexdigest(pw) == c.password # start a session with the customer id @session[''customer''] = c.id if @cart.products.empty? redirect_to :controller => "catalog" else redirect_to :controller => "checkout", :action => "index" end else # otherwise report an error flash[:notice] = "Invalid Login" end end def logout @session[''customer''] = nil redirect_to :controller => "catalog" end And in my application.rb controller: # register the method get_customer as a filter before_filter :get_customer def get_customer # sets an instance variable @c to the customer object # drawn from the db record of the customer who''s logged in # else the method is not assigned to @c and @c defaults to nil if @session[''customer''] @c = Customer.find(@session[''customer'']) end end This login method is taken from "Ruby from Rails" book, Part 4, which I am going to use next to change my current cart. I am going to change it that both cart and checkout are in the same controller because I need the cart to belongs_to :customer. The reason is that I need to apply the customer''s discount level and I also want to record the customer''s id in the orders table. (optional later, I will add the option to remember customer''s shipping address.) This has been a huge learning curve for me. I''m happy (and tired) that it finally works. I''m off to re-do my cart. If you have any suggestions/improvements to my code or way of thinking, please share your thoughts. Just one last question, when I create a session, does the information for session[''customer''] and session[:cart_id] get stored in the same file? and How do I call on the customer_id from the session? Have run into trouble with this, where the order recorded the order_id in the customer_id column. Not sure where is my mistake yet. Cheers, Elle --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Each session is stored in a single file in binary format. It looks like you are storing the customer id as session["customer"] so you can just reference it like that. Can you post your code with the order_id problem? On Oct 14, 10:10 pm, elle <wazne...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I ended up with the following: > 1) For admin pages: I used acts_as_authenticated plugin for users (and > by users I mean admins). > > My aaplication.rb controller has: > class ApplicationController < ActionController::Base > include AuthenticatedSystem > ... > > My base_controller.rb for the admin area inherits from the > ApplicationController and also has a before_filter: > class Admin::BaseController < ApplicationController > before_filter :login_required > end > > And all my admin pages inherit from the base controller by using: > class Admin::UserController < Admin::BaseController > ... > Which means, they all require login to be viewed. > > In my views/layout/application.rhtml I have: > <p id="adminlogin"> > <% if logged_in? %> > Logged in as <%= current_user.login %> > (<%= link_to "Logout", :controller => "/admin", :action => > "logout" %>) > <% else %> > <%= link_to "Admin Login", :controller => "/admin", :action => > "login" %> > <% end %> > </p> > > 2) Next, I added another column in my users table called > ''role'' (:integer, :limit => 1) to identify 1 for manager and 0 for > staff. > Only managers can add admins. Staff can do everything else in the > admin area besides administering admins. > So, in my user_controller.rb I added another before_filter: > > before_filter :check_authorization > > def check_authorization > user = User.find(session[:user]) > unless user.role? > flash[:notice] = "You are not authorized to view the page > requested" > redirect_to :controller => ''product'', :action => ''index'' > return false > end > end > > 3) Lastly, I created a customer model which admins can create, > edit.... > Now, only logged customers can checkout. So, in my checkout controller > I added all my customer''s login methods, like so: > > class CheckoutController < ApplicationController > before_filter :initialize_cart > before_filter :authorize, :except => ["login"] > > def authorize > return true if @c > flash[:notice] = "To place your order please login" > redirect_to :controller => "catalog" > end > > def login > # examine the form data for "name" and "password" > pw,name = params[:customer].values_at(*%w{password name}) > # Retrieve the customer record for the name and store it in a > variable ''c'' > c = Customer.find_by_name(name) > # if such record exists, and it''s password matches the password > from the form > if c && Digest::SHA1.hexdigest(pw) == c.password > # start a session with the customer id > @session[''customer''] = c.id > if @cart.products.empty? > redirect_to :controller => "catalog" > else > redirect_to :controller => "checkout", :action => "index" > end > else > # otherwise report an error > flash[:notice] = "Invalid Login" > end > end > > def logout > @session[''customer''] = nil > redirect_to :controller => "catalog" > end > > And in my application.rb controller: > # register the method get_customer as a filter > before_filter :get_customer > > def get_customer > # sets an instance variable @c to the customer object > # drawn from the db record of the customer who''s logged in > # else the method is not assigned to @c and @c defaults to nil > if @session[''customer''] > @c = Customer.find(@session[''customer'']) > end > end > > This login method is taken from "Ruby from Rails" book, Part 4, which > I am going to use next to change my current cart. > I am going to change it that both cart and checkout are in the same > controller because I need the cart to belongs_to :customer. > The reason is that I need to apply the customer''s discount level and I > also want to record the customer''s id in the orders table. > (optional later, I will add the option to remember customer''s shipping > address.) > > This has been a huge learning curve for me. I''m happy (and tired) that > it finally works. I''m off to re-do my cart. > If you have any suggestions/improvements to my code or way of > thinking, please share your thoughts. > > Just one last question, when I create a session, does the information > for session[''customer''] and session[:cart_id] get stored in the same > file? > and How do I call on the customer_id from the session? Have run into > trouble with this, where the order recorded the order_id in the > customer_id column. Not sure where is my mistake yet. > > Cheers, > Elle--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
The basics are: (1) When an admin requests to become another user, I set a session variable called: session[:effective_user] = User.find_by_login("whatever") (2) When they stop being that user, I delete that entry from the session hash. (3) When I set up my current_user pseudo-global, I set it to the effective user if it is set, or to the real user (in session[:user]) if it is not set. (4) I set real_user to session[:user] (5) Once those are set up, I verify that this is true: current_user == real_user || real_user.is_site_admin? This prevents a mistake from letting someone become another user where they should not. (6) In most places, I use current_user for all access checking, display, and database updates. (7) In specific places where I want the admin to be warned (deleting data, changing data in some cases, and also on a "WARNING: you are logged in as ..." on the sidebar menu) I check to see if real_user !current_user && current_user.is_site_admin? Since I use current_user nearly everywhere, this was the path of least rototill for me :) --Michael --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
This is slightly different but still on the same subject. So, I got the customer to log in, but.... he doesn''t have a cart that belongs to him. Which means if another customer logs in, they see the other''s cart. I want to associate the cart with a customer to also be able to record the customer''s id in the orders table. but.... I don''t know how to do that. Other problems that I have with my cart are: 1) Update doesn''t happen 2) checkout page suddenly doesn''t appear Will you have a look at how I can associate the cart with the logged in customer? (And if you can at the other questions/problems) My cart.rb: -------------------- class Cart < ActiveRecord::Base has_many :cart_items has_many :products, :through => :cart_items belongs_to :customer def total cart_items.inject(0) {|sum, n| n.price * n.amount + sum} end def add(product_id) items = cart_items.find_all_by_product_id(product_id) product = Product.find(product_id) if items.size < 1 ci = cart_items.create(:product_id => product_id, :amount => 1, :price => product.price) else ci = items.first ci.update_attribute(:amount, ci.amount + 1) end ci end def remove(product_id) ci = cart_items.find_by_product_id(product_id) if ci.amount > 1 ci.update_attribute(:amount, ci.amount - 1) else CartItem.destroy(ci.id) end return ci end def update(product_id) ci = cart_items.find_by_product_id(product_id) ci.update_attribue(:amount => new_qty.to_i ) end end My cart_controller: ------------------------------ class CartController < ApplicationController before_filter :initialize_cart before_filter :authorize, :except => ["login"] def authorize return true if @c flash[:notice] = "To place your order please login" redirect_to :controller => "catalog" end def login # examine the form data for "name" and "password" pw,name = params[:customer].values_at(*%w{password name}) # Retrieve the customer record for the name and store it in a variable ''c'' c = Customer.find_by_name(name) # if such record exists, and it''s password matches the password from the form if c && Digest::SHA1.hexdigest(pw) == c.password # start a session with the customer id @session[''customer''] = c.id if @cart.products.empty? redirect_to :controller => "catalog" else redirect_to :action => "view_cart" end else # otherwise report an error flash[:notice] = "Invalid Login" redirect_to :controller => "catalog" end end def logout @session[''customer''] = nil redirect_to :controller => "catalog" end def index end def add @product = Product.find(params[:id]) if request.post? @item = @cart.add(params[:id]) flash[:notice] = "Added <em>#{@item.product.title}</em> to cart." redirect_to :controller => "catalog" else render end end def update @product = Product.find(params[:id]) new_qty = params[:new_qty] if request.post? @item = @cart.update(params[:id], new_qty) flash[:notice] = "Updated <em>#{@item.product.title}</em>''s quantity." redirect_to :action => "view_cart" else render end end def remove @product = Product.find(params[:id]) if request.post? @item = @cart.remove(params[:id]) flash[:notice] = "Removed <em>#{@item.product.title}</em>" redirect_to :action => "view_cart" else render end end def clear if request.post? @cart.cart_items.destroy_all flash[:notice] = "Cleared the cart" redirect_to :controller => "catalog" else render end end def view_cart @page_title = "Shopping Cart for #{@c.name}" @order = Order.new if @cart.products.empty? flash[:notice] = "Your shopping cart is empty! Please add something to it before proceeding to checkout." redirect_to :controller => ''catalog'' end end def checkout @page_title = "Checkout" @order = Order.new(params[:order]) @order.customer_ip = request.remote_ip @order.customer_id = @session[''customer''] populate_order if @order.save if @order.process flash[:notice] = ''Your order has been submitted, and will be processed immediately.'' session[:order_id] = @order.id # Empty the cart @cart.cart_items.destroy_all redirect_to :action => ''thank_you'' else flash[:notice] = "Error while placing order. ''#{@order.error_message}''" render :action => ''view_cart'' end else render :action => ''view_cart'' end end def thank_you @page_title = ''Thank You!'' end def populate_order for cart_item in @cart.cart_items order_item = OrderItem.new( :product_id => cart_item.product_id, :price => cart_item.price, :amount => cart_item.amount ) @order.order_items << order_item end end end And _item.rhtml which part of the view_cart.rhtml: ---------------------------------------- <tr> <td><%=h item.product.sku %></td> <td><%= link_to item.product.title, :action => "show", :controller => "catalog", :id => item.product.id %></td> <td><%= pluralize(item.amount, "pc", "pcs") %></td> <td>$<%= two_dec(item.price * item.amount) %></td> <td><%= form_tag :controller => "cart", :action => "update", :id => item.product, :with => "new_qty" %> <%= text_field_tag "new_qty", "", "size" => 4 %> <input type="Submit", value="Update"/> <%= end_form_tag %> </td> <td><%= button_to "x", :controller => "cart", :action => "remove", :id => item.product %></td> </tr> Now tell me the truth, how messy is my code? where are my mistakes? Thanks, Elle --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
You have a belongs_to :customer in your cart.rb, make sure you have a customer_id field integer in your carts table. Where is the initialize_cart method? On Oct 16, 5:29 am, elle <wazne...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> This is slightly different but still on the same subject. > So, I got the customer to log in, but.... he doesn''t have a cart that > belongs to him. Which means if another customer logs in, they see the > other''s cart. I want to associate the cart with a customer to also be > able to record the customer''s id in the orders table. but.... I don''t > know how to do that. > > Other problems that I have with my cart are: > 1) Update doesn''t happen > 2) checkout page suddenly doesn''t appear > > Will you have a look at how I can associate the cart with the logged > in customer? (And if you can at the other questions/problems) > > My cart.rb: > -------------------- > class Cart < ActiveRecord::Base > has_many :cart_items > has_many :products, :through => :cart_items > belongs_to :customer > > def total > cart_items.inject(0) {|sum, n| n.price * n.amount + sum} > end > > def add(product_id) > items = cart_items.find_all_by_product_id(product_id) > product = Product.find(product_id) > if items.size < 1 > ci = cart_items.create(:product_id => product_id, > :amount => 1, > :price => product.price) > else > ci = items.first > ci.update_attribute(:amount, ci.amount + 1) > end > ci > end > > def remove(product_id) > ci = cart_items.find_by_product_id(product_id) > > if ci.amount > 1 > ci.update_attribute(:amount, ci.amount - 1) > else > CartItem.destroy(ci.id) > end > return ci > end > > def update(product_id) > ci = cart_items.find_by_product_id(product_id) > ci.update_attribue(:amount => new_qty.to_i ) > end > > end > > My cart_controller: > ------------------------------ > class CartController < ApplicationController > before_filter :initialize_cart > before_filter :authorize, :except => ["login"] > > def authorize > return true if @c > flash[:notice] = "To place your order please login" > redirect_to :controller => "catalog" > end > > def login > # examine the form data for "name" and "password" > pw,name = params[:customer].values_at(*%w{password name}) > # Retrieve the customer record for the name and store it in a > variable ''c'' > c = Customer.find_by_name(name) > # if such record exists, and it''s password matches the password > from the form > if c && Digest::SHA1.hexdigest(pw) == c.password > # start a session with the customer id > @session[''customer''] = c.id > > if @cart.products.empty? > redirect_to :controller => "catalog" > else > redirect_to :action => "view_cart" > end > else > # otherwise report an error > flash[:notice] = "Invalid Login" > redirect_to :controller => "catalog" > end > end > > def logout > @session[''customer''] = nil > redirect_to :controller => "catalog" > end > > def index > end > > def add > @product = Product.find(params[:id]) > if request.post? > @item = @cart.add(params[:id]) > flash[:notice] = "Added <em>#...@item.product.title}</em> to > cart." > redirect_to :controller => "catalog" > else > render > end > end > > def update > @product = Product.find(params[:id]) > new_qty = params[:new_qty] > if request.post? > @item = @cart.update(params[:id], new_qty) > flash[:notice] = "Updated <em>#...@item.product.title}</em>''s > quantity." > redirect_to :action => "view_cart" > else > render > end > end > > def remove > @product = Product.find(params[:id]) > if request.post? > @item = @cart.remove(params[:id]) > flash[:notice] = "Removed <em>#...@item.product.title}</em>" > redirect_to :action => "view_cart" > else > render > end > end > > def clear > if request.post? > @cart.cart_items.destroy_all > flash[:notice] = "Cleared the cart" > redirect_to :controller => "catalog" > else > render > end > end > > def view_cart > @page_title = "Shopping Cart for #...@c.name}" > @order = Order.new > if @cart.products.empty? > flash[:notice] = "Your shopping cart is empty! Please add > something to it before proceeding to checkout." > redirect_to :controller => ''catalog'' > end > end > > def checkout > @page_title = "Checkout" > @order = Order.new(params[:order]) > @order.customer_ip = request.remote_ip > @order.customer_id = @session[''customer''] > populate_order > > if @order.save > if @order.process > flash[:notice] = ''Your order has been submitted, and will be > processed immediately.'' > session[:order_id] = @order.id > # Empty the cart > @cart.cart_items.destroy_all > redirect_to :action => ''thank_you'' > else > flash[:notice] = "Error while placing order. > ''...@order.error_message}''" > render :action => ''view_cart'' > end > else > render :action => ''view_cart'' > end > end > > def thank_you > @page_title = ''Thank You!'' > end > > def populate_order > for cart_item in @cart.cart_items > order_item = OrderItem.new( > :product_id => cart_item.product_id, > :price => cart_item.price, > :amount => cart_item.amount > ) > @order.order_items << order_item > end > end > > end > > And _item.rhtml which part of the view_cart.rhtml: > ---------------------------------------- > <tr> > <td><%=h item.product.sku %></td> > <td><%= link_to item.product.title, :action => "show", > :controller => "catalog", :id => item.product.id %></td> > <td><%= pluralize(item.amount, "pc", "pcs") %></td> > <td>$<%= two_dec(item.price * item.amount) %></td> > > <td><%= form_tag :controller => "cart", :action => "update", :id => > item.product, :with => "new_qty" %> > <%= text_field_tag "new_qty", "", "size" => 4 %> > <input type="Submit", value="Update"/> > <%= end_form_tag %> > </td> > <td><%= button_to "x", :controller => "cart", :action => "remove", :id > => item.product %></td> > </tr> > > Now tell me the truth, how messy is my code? where are my mistakes? > > Thanks, > Elle--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Should I start a session[:cart] and add the customer_id to it? would rails then see all the columns in the cart_items table? Or should I leave it as session[:customer]? On Oct 20, 6:33 am, "randomutterings..." <randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> You have a belongs_to :customer in your cart.rb, make sure you have a > customer_id field integer in your carts table. Where is the > initialize_cart method?--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I don''t think that would help. Your cart model has a before_filter called initialize_cart. I''m assuming that is what creates the cart and stores it in the database as I cannot see where that is happening. I would assume that initialize_cart should look something like this. def initialize_cart cart = Cart.new cart.customer_id = session[:customer_id] cart.save end On Oct 20, 1:50 am, elle <wazne...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Should I start a session[:cart] and add the customer_id to it? would > rails then see all the columns in the cart_items table? > Or should I leave it as session[:customer]? > > On Oct 20, 6:33 am, "randomutterings..." <randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > wrote: > > > You have a belongs_to :customer in your cart.rb, make sure you have a > > customer_id field integer in your carts table. Where is the > > initialize_cart method?--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I should have posted my solution before. I ended up creating a new [:customer] session at login as well as a session{:cart]. In the carts table, I inserted the customer_id. The relationships are: class Customer < ActiveRecord::Base has_many :orders, :dependent => true, :order => "created_at ASC" has_one :cart class Cart < ActiveRecord::Base has_many :cart_items has_many :products, :through => :cart_items belongs_to :customer Then when the customer logs off, I set: session[:customer] = nil session[:cart] = nil Works great. The app remembers customer''s cart when he logs in next time. I got help with this as well (wish I knew the person''s name to give credit). Cheers, Elle On Oct 24, 1:49 am, "randomutterings..." <randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I don''t think that would help. Your cart model has a before_filter > called initialize_cart. I''m assuming that is what creates the cart > and stores it in the database as I cannot see where that is > happening. I would assume that initialize_cart should look something > like this. > > def initialize_cart > cart = Cart.new > cart.customer_id = session[:customer_id] > cart.save > end > > On Oct 20, 1:50 am, elle <wazne...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > Should I start a session[:cart] and add the customer_id to it? would > > rails then see all the columns in the cart_items table? > > Or should I leave it as session[:customer]? > > > On Oct 20, 6:33 am, "randomutterings..." <randomutteri...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > > wrote: > > > > You have a belongs_to :customer in your cart.rb, make sure you have a > > > customer_id field integer in your carts table. Where is the > > > initialize_cart method?--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---