Как лучше связать адрес с несколькими моделями в рельсах? - PullRequest
11 голосов
/ 13 октября 2010

Этот вопрос в SO, похоже, связан с моим вопросом, но я не уверен, что на этот вопрос мне дан ответ.

Адрес может принадлежать более чем одной модели (UserProfile и Event) Как правильно реализовать это?

Основные таблицы:

user_profiles(id)
events(id)

Варианты реализации адресов таблица:

  1. addresses(id,user_profile_id,event_id)
    Этот подход кажется глупым, поскольку, если завтра адрес должен принадлежать еще одной модели, я должен добавить это поле id.
    Кроме того, я пока не знаю, но добавление нового поля id может также привести к поломке некоторого кода?

  2. addresses(id,model_type,model_id)
    Это полиморфно, верно.Я не знаю почему, но я как-то опасаюсь этого?

  3. Каким-то другим способом это сделать?

Примечание :

Я мог бы создать такие таблицы, я полагаю:

user_profiles(id,address_id)
events(id,address_id)

Но этоозначает, что один и тот же address_id может принадлежать разным моделям.Я полагаю, что это не должно быть так, потому что, например, скажем, что адрес для события должен быть изменен, но это не должно влиять на адрес user_profile.Так что это будет что-то вроде этого (что я считаю неправильным):

@current_user_profile.address = some_new_address
#this would have changed the address for both the user_profile *and* the event
@current_user_profile.save 

Ответы [ 2 ]

11 голосов
/ 14 октября 2010

Одним из способов будет стандартный полиморфизм Rails:

class Address
  belongs_to :addressable, :polymorphic => true
end

class UserProfile
  has_one address, :as => :addressable
end

class Event
  has_one address, :as => :addressable
end

Это может быть неприятное чувство, которое вы испытываете по этому поводу, что вы не можете создать ограничение уровня db с полиморфными отношениями в стиле Rails. Альтернатива (предложенная Дэном Чаком в Enterprise Rails ) похожа на ваш вариант № 1, где вы действительно создаете отдельное поле id для каждого типа отношений. Это оставляет неиспользуемые поля, но также учитывает ограничения. Я могу видеть аргумент для обоих, но сообщество Rails уже некоторое время использует AR полиморфизм с явно хорошим успехом. Я использую это без колебаний. Но если это вас не устраивает, вы можете использовать подход Чака. Это намного больше работы. :)

РЕДАКТИРОВАТЬ: @ Slick86, миграция будет выглядеть примерно так:

class CreateAddresses < ActiveRecord::Migration
  def change
    create_table :addresses do |t|
      t.integer :addressable_id
      t.string :addressable_type
    end
  end
end
11 голосов
/ 13 октября 2010

Вы пропустили один вариант: иметь класс, который содержит общее поведение, и добавлять поля во все таблицы.Используйте составной_компонент для управления данными.

class Address
  attr_accessor :line1, :line2, :city, :state, :zip

  def initialize(line1, line2, city, state, zip)
    @line1 = line1
  end
end

class UserProfile < ActiveRecord::Base
  composed_of :address, :mapping => %w(line1 line2 city state zip)
end

class Event < ActiveRecord::Base
  composed_of :address, :mapping => %w(line1 line2 city state zip)
end

См. # comped_of в документации по Ruby on Rails API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...