0

Я пытаюсь определить подходящий способ установки следующей схемы и ассоциации в Rails 4:В Rails, как подключить модель дважды к другой модели, которую она полиморфно принадлежит?

Business 
    company_name 
    ->1 street_address (Address) 
    ->0..1 mailing_address (Address) 
    ->0..n employees (Employee) 

Employee 
    first_name 
    last_name 
    birthday 
    ->0..n addresses (Address) 

Address 
    street 
    city 
    state 
    zip 
    ->1 resource (Business or Employee or potentially something else in the future) 

Основными задачами здесь являются:

  1. , чтобы иметь возможность получить произвольный адрес и в свою очередь, найти ресурс, к которому он принадлежит (который может быть Бизнес или Работодателем)
  2. иметь один адрес, обозначенный как «адрес улицы» для каждого Бизнеса, и необязательно другой адрес в качестве «почтового адреса»
  3. , чтобы каждый бизнес имел несколько сотрудников, каждый из которых может иметь другие разные адреса (домашний адрес и т. Д.).
  4. , чтобы в будущем и другие ресурсы (пока еще неизвестно) также ассоциировали Адреса

Обратите внимание, что адрес может либо принадлежать к бизнесу (действующий в качестве либо адрес или почтовый адрес для бизнеса) или Работнику (а сотрудник может иметь несколько адресов). Это для меня означает полиморфного отношения, и мой первый удар в реализации этого в Rails выглядит следующим образом:

class Business < ActiveRecord::Base 
    has_one :street_address, class_name: 'Address', as: :resource, 
          inverse_of: :resource, dependent: :destroy 
    has_one :mailing_address, class_name: 'Address', as: :resource, 
          inverse_of: :resource, dependent: :destroy 
    has_many :business_employees, inverse_of: :business, dependent: :destroy 
    has_many :employees, through: :business_employees 
end 

class BusinessEmpoloyee < ActiveRecord::Base 
    belongs_to :business 
    belongs_to :employee 
end 

class Employee < ActiveRecord::Base 
    has_many :business_employees, inverse_of: :employee, dependent: :destroy 
    has_many :businesses, through: :business_employees 
    has_many :addresses, as: :resource, inverse_of: :resource, dependent: :destroy 
end 

class Address < ActiveRecord::Base 
    belongs_to :resource, polymorphic: true 
end 

Однако, это не работает, как ожидалось. Улица и почтовый адрес для бизнеса всегда возвращают одинаковое значение. Например:

2.1.2 :001 > b = Business.create(company_name: 'Test Business') 

2.1.2 :002 > b.street_address = Address.create(street: '123 Main St', city: 'San Francisco', state: 'CA') 

2.1.2 :003 > b.mailing_address = Address.create(street: 'P.O. Box 123', city: 'New York', state_code: 'NY') 

2.1.2 :004 > b2 = Business.find_by_company_name('Test Business') 
    Business Load (1.2ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."company_name" = 'Test Business' LIMIT 1 
=> #<Business id: 1168, company_name: "Test Business", street_address_id: nil, mailing_address_id: nil, created_at: "2014-09-04 19:57:14", updated_at: "2014-09-04 19:57:14"> 

2.1.2 :005 > b2.mailing_address 
    Address Load (0.5ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1 [["resource_id", 1168], ["resource_type", "Business"]] 
=> #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56"> 

2.1.2 :006 > b2.street_address 
    Address Load (0.5ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."resource_id" = $1 AND "addresses"."resource_type" = $2 LIMIT 1 [["resource_id", 1168], ["resource_type", "Business"]] 
=> #<Address id: 1186, resource_id: 1168, resource_type: "Business", street: "P.O. Box 123", city: "New York", state: "NY", zip: nil, created_at: "2014-09-04 19:57:56", updated_at: "2014-09-04 19:57:56"> 

Конечно, это имеет смысл - как Бизнес предполагают, чтобы знать который Адрес использовать для которых значение адреса?

Итак, в этом случае любые предложения по поводу того, как я могут зафиксировать отношения, описанные здесь?

ответ

0

Правило большого пальца: отношение записывается в модель, которая belongs. Если вы укажете для одной модели две ассоциации, указывающие на одну и ту же модель, они будут фактически одинаковыми, так как есть только один способ: иметь определенную модель resource_id и resource_type.

Вам нужно будет добавить еще один параметр в «принадлежность», чтобы отфильтровать «какая принадлежность». Довольно стандартный способ это одна таблица наследования (STI) (и I happened to write about how to use it), которая работает следующим образом: вы добавляете type:string:index столбец Address и создать новый класс, который наследуется от Address, скажем, MailingAddress:

class MailingAddress < Address 
end 

В большинстве случаев он должен быть пустым, он наследует все от Address, даже хранилище: оно хранится в одной таблице, но может быть выделено type="MailingAddress", которое добавляется автоматически при запросе экземпляров этого класса из базы данных. Однако, когда вы запрашиваете Address es, вы также получаете MailingAddress es, по принципу наследования.

Другие способы сделать то же самое с чем-то похожим: добавление другого столбца для фильтрации почтовых адресов от всех остальных. Строка - это не самая быстрая вещь для сравнения, хотя RDBMS безумно быстро это делают.

Смежные вопросы