Можно ли описать это отношение в Ruby on Rails? - PullRequest
5 голосов
/ 14 ноября 2009

Это отношение может быть описано в отношениях модели ActiveRecord в Ruby on Rails?

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

Чтобы у меня были данные, которые выглядят так:

Адрес:

   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 |

Заказчик:

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

Я хочу хранить адреса в их собственной таблице, поскольку данные могут совместно использоваться клиентами (особенно адрес доставки). Но для каждого конкретного клиента будет только два адреса.

Я бы хотел избежать отношений «многие ко многим», если нет другого пути.

Ответы [ 3 ]

5 голосов
/ 14 ноября 2009

Да, это вполне возможно сделать. При наличии таблицы customers с двумя внешними ключами shipping_address_id и billing_address_id для таблицы addresses ваша модель Customer может выглядеть следующим образом:

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

Это позволит клиенту ссылаться на одну и ту же строку адреса для адресов доставки и выставления счетов, а также позволит нескольким клиентам совместно использовать адреса.

Обновление: При обмене ссылками на подобные адреса вы, вероятно, захотите тщательно продумать, как обрабатывать обновления адресов. В вашем примере Боб и Ал имеют один и тот же адрес доставки. Теперь, если Боб обновляет свой адрес доставки, вы, вероятно, захотите создать новую запись Address для нового адреса Боба, а не обновить существующую запись, чтобы избежать изменения адреса Ала. Иногда вам может потребоваться обновить адреса обоих клиентов в этой ситуации, но в большинстве случаев вы, вероятно, этого не делаете.

2 голосов
/ 14 ноября 2009

Заданы следующие определения таблиц:

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

Вы можете связать адрес выставления счета и доставки с вашим клиентом следующим образом:

class Customer < ActiveRecord::Base
  belongs_to :shipping_address, :class_name => "Address"
  belongs_to :billing_address,  :class_name => "Address"
end
0 голосов
/ 14 ноября 2009

В документации для ассоциаций ActiveRecord есть раздел has_one против belongs_to. Кроме того, в разделе в has_one упоминается, что его следует использовать, только если другой класс имеет внешний ключ. Итак, для моделирования того, что вы хотите, вы бы использовали.

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

Пример использования:

>> 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">
>> 
...