Я хочу, чтобы Клиент ссылался на две модели адресов: одну для платежного адреса и одну для адреса доставки. Как я понимаю, внешний ключ определяется его именем, как _id. Очевидно, я не могу назвать две строки address_id (для ссылки на таблицу адресов). Как мне это сделать?
Ответ 2
Это может быть путаным для людей, новых для Rails (как я был недавно), потому что некоторые части ответа происходят в ваших Migrations и некоторых в ваших моделях. Кроме того, вы действительно хотите моделировать две отдельные вещи:
-
Адрес принадлежит одному клиенту, и каждый клиент имеет много адресов. В вашем случае это будет 1 или 2 адреса, но я бы посоветовал вам рассмотреть возможность того, что у клиента может быть более одного адреса доставки. В качестве примера у меня есть 3 отдельных адреса доставки с Amazon.com.
-
В отдельности мы хотим моделировать тот факт, что каждый клиент имеет адрес фактуры и адрес доставки, который может вместо этого являться адресом доставки по умолчанию, если вы разрешаете более одного адреса доставки.
Вот как вы это сделаете:
Миграция
class CreateCustomers < ActiveRecord::Migration
create_table :customers do |t|
def up
t.references :billing_address
t.references :shipping_address
end
end
end
Здесь вы указываете, что в этой таблице есть два столбца, которые будут называться: billing_address и: shipping_address и которые содержат ссылки на другую таблицу. Rails фактически создадут для вас столбцы с именем "billing_address_id" и "shipping_address_id". В нашем случае они будут ссылаться на строки ссылок в таблице Адресов, но мы укажем, что в моделях, а не в миграциях.
class CreateAddresses < ActiveRecord::Migration
create_table :addresses do |t|
def up
t.references :customer
end
end
end
Здесь вы также создаете столбец, который ссылается на другую таблицу, но вы опускаете "_id" в конце. Rails позаботится об этом для вас, потому что видит, что у вас есть таблица "клиенты", которая соответствует имени столбца (он знает о множественности).
Причина, по которой мы добавили "_id" в миграцию Клиентов, состоит в том, что у нас нет таблицы "billing_addresses" или "shipping_addresses", поэтому нам нужно вручную указать имя всего столбца.
Модели
class Customer < ActiveRecord::Base
belongs_to :billing_address, :class_name => 'Address'
belongs_to :shipping_address, :class_name => 'Address'
has_many :addresses
end
Здесь вы создаете свойство в модели Customer с именем: billing_address, а затем указываете, что это свойство связано с классом Address. Рельсы, видя "принадлежность", будут искать столбец в таблице клиентов с именем "billing_address_id", который мы определили выше, и используем этот столбец для хранения внешнего ключа. Затем вы делаете то же самое для адреса доставки.
Это позволит вам получить доступ к вашему платежному адресу и адресу доставки, оба экземпляра модели Address, через экземпляр модели Customer, например:
@customer.billing_address # Returns an instance of the Address model
@customer.shipping_address.street1 # Returns a string, as you would expect
В качестве побочного примечания: номенклатура 'belongs_to' в этом случае путаница, поскольку Адресы принадлежат Клиентам, а не наоборот. Игнорируйте свою интуицию; 'belongs_to' используется в зависимости от того, что содержит внешний ключ, который в нашем случае, как вы увидите, является одновременно и моделями. Хах! как это для смущения?
Наконец, мы указываем, что у Клиента много адресов. В этом случае нам не нужно указывать имя класса, к которому относится это свойство, потому что Rails достаточно умен, чтобы увидеть, что у нас есть модель с соответствующим именем: "Адрес", через секунду мы получим. Это позволяет нам получить список всех адресов клиентов, выполнив следующие действия:
@customer.addresses
Это вернет массив экземпляров модели Address, независимо от того, являются ли они биллинговыми или отправляющими адресами. Говоря о модели Address, вот что это выглядит:
class Address < ActiveRecord::Base
belongs_to :customer
end
Здесь вы выполняете то же самое, что и с строками 'belongs_to' в модели Customer, за исключением того, что Rails делает для вас какую-то магию; глядя на имя свойства ( "клиент" ), он видит "принадлежность" и предполагает, что это свойство ссылается на модель с тем же именем ( "Клиент" ) и что в таблице адресов имеется соответствующий столбец ( "customer_id" ).
Это позволяет нам получить доступ к Клиенту, который принадлежит адресу:
@address.customer # Returns an instance of the Customer model
@address.customer.first_name # Returns a string, as you would expect
Ответ 3
Я понял, как это сделать благодаря Тоби:
class Address < ActiveRecord::Base
has_many :customers
end
class Customer < ActiveRecord::Base
belongs_to :billing_address, :class_name => 'Address', :foreign_key => 'billing_address_id'
belongs_to :shipping_address, :class_name => 'Address', :foreign_key => 'shipping_address_id'
end
Таблица клиентов включает в себя столбцы shipping_address_id и billing_address_id.
Это, по существу, отношение has_two. Я нашел этот поток полезный.