2009-11-14 25 views
5

¿Es esta una relación que se puede describir en las relaciones del modelo ActiveRecord de Ruby on Rails?¿Se puede describir esta relación en Ruby on Rails?

Customer       Address 
    ===================    ========= 
    Billing_Address_Id >------} 
           }---|- AddressId 
    Shipping_Address_Id >------} 

para que yo pudiera tener datos que se parece a esto:

Dirección:

Id | Addr   | City  | State | Zip | 
    ================================================ 
    1 | 123 Main  | New York | NY | 99999 | 
    2 | 200 2nd Street | New York | NY | 99999 | 
    3 | 300 3rd Street | Albany | NY | 99998 | 
    4 | PO Box 4  | Albany | NY | 99998 | 

cliente:

Id | Name | Billing_Address_Id | Shipping_Address_Id | 
    ======================================================= 
    1 | Bob | 1     | 1     | 
    2 | Al | 2     | 1     | 
    3 | Joe | 3     | 4     | 

quiero para almacenar direcciones en su propia mesa, ya los datos pueden ser compartidos entre los clientes (especialmente la dirección de envío). Pero solo habría dos direcciones para un cliente determinado.

Me gustaría evitar una relación de muchos a muchos a menos que no haya otra forma.

Respuesta

2

definiciones de la tabla indican de esta forma:

create_table :addresses do |t| 
    t.string :street 
    t.string :city 
    t.string :state 
    t.string :zip 
    t.timestamps 
end 

create_table :customers do |t| 
    t.string  :name 
    t.references :shipping_address 
    t.references :billing_address 
    t.timestamps 
end 

puede asociar una dirección de facturación y de envío con su cliente como esto:

class Customer < ActiveRecord::Base 
    belongs_to :shipping_address, :class_name => "Address" 
    belongs_to :billing_address, :class_name => "Address" 
end 
+0

El diseño de la tabla ayudará. No estaba al tanto de las "referencias tipo de datos". – y0mbo

5

Sí, es perfectamente posible hacer eso. Dada una tabla customers con las dos claves externas shipping_address_id y a la mesa addresses, su modelo Customer podría tener este aspecto:

class Customer < ActiveRecord::Base 
    belongs_to :billing_address, :class_name => 'Address' 
    belongs_to :shipping_address, :class_name => 'Address' 
end 

Esto le permitirá una referencia al cliente la misma fila de direcciones para las direcciones de envío y facturación, y la voluntad también permita que varios clientes compartan direcciones.

Actualización: Al compartir referencias a direcciones como esta, es probable que desee considerar cuidadosamente cómo manejar las actualizaciones de direcciones. En su ejemplo, Bob y Al comparten la misma dirección de envío. Ahora, si Bob actualiza su dirección de envío, probablemente desee crear un nuevo registro Address para la nueva dirección de Bob en lugar de actualizar el registro existente, para evitar cambiar también la dirección de Al. En ocasiones, es posible que desee actualizar las direcciones de ambos clientes en esta situación, pero en la mayoría de los casos probablemente no lo haga.

+0

Estoy de acuerdo con su evaluación de diseño. Mi ejemplo está un poco simplificado de lo que realmente estaré haciendo; los clientes serían realmente parte de la misma cuenta en el mismo hogar. Pueden compartir la misma dirección o pueden desear el envío a una ubicación diferente. – y0mbo

0

The documentation for ActiveRecord associations has a section on has_one vs belongs_to. Además, el section on has_one menciona que este debe ser usada solamente si la otra clase tiene la clave externa. Entonces, para modelar lo que quieras, usarías.

class Address < ActiveRecord::Base 
    has_one :shipto_customer, :class_name => "Customer", :foreign_key => "shipping_address_id" 
    has_one :billto_customer, :class_name => "Customer", :foreign_key => "billing_address_id" 
end 

class Customer < ActiveRecord::Base 
    belongs_to :shipping_address, :class_name => "Address" 
    belongs_to :billing_address, :class_name => "Address" 
end 

Ejemplo de uso:

>> customer = Customer.new(:name => "John Smith", 
?>  :shipping_address => Address.new(:address => "123 M St", 
?>  :city => "Phoenix", :state => "AZ", :zip => "85015"), 
?>  :billing_address => Address.new(:address => "555 W Main Dr", 
?>  :city => "Phoenix", :state => "AZ", :zip => "85015") 
>> ) 
=> #<Customer id: nil, name: "John Smith", billing_address_id: nil, shipping_address_id: nil, created_at: nil, updated_at: nil> 
>> customer.save 
    Address Create (0.8ms) INSERT INTO "addresses" ("address", "city", "zip", "created_at", "updated_at", "state") VALUES('555 W Main Dr', 'Phoenix', '85015', '2009-11-14 17:03:28', '2009-11-14 17:03:28', 'AZ') 
    Address Create (0.2ms) INSERT INTO "addresses" ("address", "city", "zip", "created_at", "updated_at", "state") VALUES('123 M St', 'Phoenix', '85015', '2009-11-14 17:03:28', '2009-11-14 17:03:28', 'AZ') 
    Customer Create (0.2ms) INSERT INTO "customers" ("name", "billing_address_id", "shipping_address_id", "created_at", "updated_at") VALUES('John Smith', 1, 2, '2009-11-14 17:03:28', '2009-11-14 17:03:28') 
=> true 
>> customer.shipping_address 
=> #<Address id: 2, address: "123 M St", city: "Phoenix", state: "AZ", zip: "85015", created_at: "2009-11-14 17:03:28", updated_at: "2009-11-14 17:03:28"> 
>> customer.billing_address 
=> #<Address id: 1, address: "555 W Main Dr", city: "Phoenix", state: "AZ", zip: "85015", created_at: "2009-11-14 17:03:28", updated_at: "2009-11-14 17:03:28"> 
>> 
+0

OP deseaba poder compartir direcciones entre clientes, por lo que las relaciones en el modelo 'Address' deberían ser' has_many' en lugar de 'has_one'. –

+0

No parece muy claro desde la publicación de OP, en el ejemplo de datos que muestra las direcciones que se comparten, es decir: has_many, en el ejemplo de código que está sugiriendo has_one. Luego dice que preferiría no tener muchos a muchos. En mi opinión, las direcciones compartidas serían una mala idea. ¿Qué sucede cuando el cliente A actualiza su dirección actual para agregar un zip + 4 o un número Apt? –

+0

Sí, las direcciones compartidas son definitivamente problemáticas. Mantener las direcciones y los clientes en tablas separadas es probablemente una buena idea para mayor claridad, pero compartir referencias a las filas de direcciones probablemente causará problemas a la hora de decidir cómo manejar las actualizaciones de direcciones. –