Rick, thanks for responding. I appreciate the help.

I wasn't familiar with scoping but after re



On Nov 21, 4:27 pm, Rick DeNatale <[email protected]> wrote:
> On Sat, Nov 21, 2009 at 4:09 AM, bui <[email protected]> wrote:
> > Hi -  Very new to RoR.  I have looked around at different strategies
> > for handling shipping and billing addresses for an e-commerce
> > applications.  What I am trying to do is to have a user registration
> > form where the user need to also fill out the default shipping
> > address.  Ultimately, I would like for the users to be able to add
> > additional shipping address and billing addresses.
>
> > I am sort of going down the path outlined by ryanb's here and using
> > Single Table Inheritance where the shipping address and billing
> > address inherits from address class.  Is this the best approach?
>
> > ryanb suggested something along the lines below:
>
> >    Customer
> >    has_many :addresses
> >    has_many :orders
>
> >    Address
> >    belongs_to :customer
>
> >    Order
> >    belongs_to :customer
> >    belongs_to :billing_address #...
> >    belongs_to :shipping_address #...
>
> > Is this an instance where I need to use both STI and polymorphic
> > association?
>
> No I don't think you need either.  You have a case where an Order can
> have two different addresses, but they are both always Addresses.
>

How do I distinguish between when an address is a shipping and when it
is a billing address? How does it get stored in the database?


>
> > I haven't created the order.rb model yet, but ryanb did suggest making
> > sure that...
>
> >    "The billing_address_id column would go in the orders table. Same
> > with the shipping."
>
> > Is this the only table in the database that would contain this
> > column?  Should they also exist in the address table or is this
> > handled by Rails through the type column?
>
> I don't think that they need to be in the address table, in this case.
>  Let's see.
>

So, I'm assuming the type column will be used.


>
> > Here's my current code but I'm certain I'm missing some key concepts
> > here.  I am providing some of the code below. Any help would be
> > greatly appreciated.
>
> > users_controller.rb
> > ************************************************
> > class UsersController < ApplicationController
> > user.rb model:
> > ************************************************
> > class User < ActiveRecord::Base
> >  acts_as_authentic
> >  has_many :addresses
> >  accepts_nested_attributes_for :addresses, :allow_destroy => true
>
> >  def address_attributes=(address_attributes)
> >    address_attributes.each do |attributes|
> >      addresses.build(attributes)
> >    end
> >  end
>
> > How do I make the default registration address be the default
> > shipping_address?  I am using address here but should it be
> > shipping_address?  Should I use a hidden field to set the type and
> > modify the create section of the code?
>
> This isn't really an issue with the user model.  User's don't have a
> shipping address, they just have one or more addresses.  Now they
> might have one of those addresses be the one they normal want orders
> shipped to.
>
> I'll get to setting the defaults for a order at the end.
>
>
>
> > ************************************************
>
> > addresses_controller.rb
> > ************************************************
> > class AddressesController < ApplicationController
> >  # GET /addresses
> >  # GET /addresses.xml
>
> >  def index
> >   �...@addresses = Address.all
>
> >    respond_to do |format|
> >      format.html # index.html.erb
> >      format.xml  { render :xml => @addresses }
> >    end
> >  end
>
> >  # GET /addresses/1
> >  # GET /addresses/1.xml
> >  def show
> >   �...@address = Address.find(params[:id])
>
> >    respond_to do |format|
> >      format.html # show.html.erb
> >      format.xml  { render :xml => @address }
> >    end
> >  end
>
> >  # GET /addresses/new
> >  # GET /addresses/new.xml
> >  def new
> >   �...@address = Address.new
>
> >    respond_to do |format|
> >      format.html # new.html.erb
> >      format.xml  { render :xml => @address }
> >    end
> >  end
>
> >  # GET /addresses/1/edit
> >  def edit
> >   �...@address = Address.find(params[:id])
> >  end
>
> >  # POST /addresses
> >  # POST /addresses.xml
> >  def create
> >   �...@address = Address.new(params[:address])
>
> >    respond_to do |format|
> >      if @address.save
> >        flash[:notice] = 'Address was successfully created.'
> >        format.html { redirect_to(@address) }
> >        format.xml  { render :xml => @address, :status
> > => :created, :location => @address }
> >      else
> >        format.html { render :action => "new" }
> >        format.xml  { render :xml => @address.errors, :status
> > => :unprocessable_entity }
> >      end
> >    end
> >  end
>
> >  # PUT /addresses/1
> >  # PUT /addresses/1.xml
> >  def update
> >   �...@address = Address.find(params[:id])
>
> >    respond_to do |format|
> >      if @address.update_attributes(params[:address])
> >        flash[:notice] = 'Address was successfully updated.'
> >        format.html { redirect_to(@address) }
> >        format.xml  { head :ok }
> >      else
> >        format.html { render :action => "edit" }
> >        format.xml  { render :xml => @address.errors, :status
> > => :unprocessable_entity }
> >      end
> >    end
> >  end
>
> >  # DELETE /addresses/1
> >  # DELETE /addresses/1.xml
> >  def destroy
> >   �...@address = Address.find(params[:id])
> >   �[email protected]
>
> >    respond_to do |format|
> >      format.html { redirect_to(addresses_url) }
> >      format.xml  { head :ok }
> >    end
> >  end
> > end
> > ************************************************
>
> The main comment I've got about this, is that if every address belongs
> to a user, then the address controller should be scoped to a user, and
> instead of Address.find, Address.new, Address.create you should find
> instantiate and create addresses using the addresses association of
> user.
>
Yes, you are correct.  I was not familiar with the scoping aspect of
rails and after some reading it appears that it is probably good
practice since without it any user can change another users address.
That's sort of what I gathered from reading about it.
>
>
>
> > address.rb model
> > ************************************************
> > class Address < ActiveRecord::Base
> >  belongs_to :user
> > end
> > ************************************************
>
> > billing_address.rb
> > ************************************************
> > class BillingAddress < Address
> > end
> > ************************************************
>
> > shipping_address.rb
> > ************************************************
> > class ShippingAddress < Address
> > end
> > ************************************************
>
> You don't need subclasses unless there is a behavioral difference
> between billing and shipping addresses.  I doubt that there is, they
> are both addresses, it's just that they are playing different roles.
>
> If you change the Order model slightly
>
> Order
>    belongs_to :customer
>    belongs_to :billing_address, :class_name => 'Address'
>    belongs_to :shipping_address, :class_name => 'Address'
>
> Then you can use the Address class for both roles.
>

Again, I understand what you are saying here, but where (i.e. - in the
address table and using the type column or in their own tables) would
the shipping and billing addresses be stored or designated in the
database?

> Now having gotten here, you could also model the notion of a customer
> having a preferred shipping address (and even a preferred billing
> address) in a similar way
>
>  User
>    ...
>   belongs_to :preferred_billing_address, :class_name => "Address"
>   belongs_to :preferred_shipping_address, :class_name => "Address"
>
> It might seem odd to have a User 'belonging to' two particular
> addresses, but you can alternatively thing of belongs_to as
> has_a_pointer_to, and has_many as has_many_pointing_to_me.
>
> Now about the order. I think that there are at least two ways of
> dealing with the billing and shipping addresses:
>
> 1) in the OrdersController
>
>      def new
>           @order = current_user.orders.build(
>                                :billing_address =>
> current_user.preferred_billing_address,
>                                :shipping_address =>
> current_user.preferred_shipping_address
>                          )
>         #...
>       end
>
> 2) in the OrderModel
>
>    class Order < ActiveRecord::Base
>           belongs_to :customer
>           belongs_to :billing_address, :class_name => 'Address'
>           belongs_to :shipping_address, :class_name => 'Address'
>
>           def after_initialize
>               if new_record?
>                  self.billing_address =
> customer.preferred_billing_address unless billing_address
>                   self.shipping_address =
> customer.preferred_shipping_address unless shipping_address
>               end
>           end
>     end
>
> The first approach is probably more conventional.
>
> HTH
>
> --
> Rick DeNatale
>
> Blog:http://talklikeaduck.denhaven2.com/
> Twitter:http://twitter.com/RickDeNatale
> WWR:http://www.workingwithrails.com/person/9021-rick-denatale
> LinkedIn:http://www.linkedin.com/in/rickdenatale

--

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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.


Reply via email to