Rails - два внешних ключа на одной модели, обе ссылаются на одну модель - PullRequest
11 голосов
/ 07 февраля 2012

Я довольно новичок в ассоциациях ActiveRecord. Я делаю набросок приложения, которое отслеживает, кто должен друг другу деньги среди множества пользователей. Модель Expense и модель User кажутся естественным выбором, я просто не уверен, как определить отношения между ними. Например, я хочу отслеживать кредитора («владельца») и должника по каждому расходу, но на самом деле это всего лишь два внешних ключа, которые возвращаются пользователю. Кроме того, у каждого пользователя может быть несколько расходов (как в качестве кредитора, так и в отношении должника). Насколько я могу судить об ассоциациях на данный момент, что-то вроде:

class Expense
    # belongs_to or has_one here?
    # Not sure about class => User syntax:
    # need to alias to foreign keys that reference the same model
    belongs_to :creditor, :class => User 
    belongs_to :debtor, :class => User

class User
    # has_many expenses defines a creditor relationship (user owns expense)
    # how to define debtor relationship? (belongs_to...?)
    has_and_belongs_to_many :expenses

Я читал руководство Rails по ассоциациям, но я все еще довольно потерян по внешним ключам и таблицам соединений. Любой вклад очень ценится!

Ответы [ 3 ]

24 голосов
/ 07 февраля 2012

Так что это определенно не has_and_belongs_to_many, это для отношений «многие ко многим».Вам просто нужно использовать пару has_many отношений.Я думаю, что это должно выглядеть так:

Редактировать: упс

18 голосов
/ 24 апреля 2012

Другие ответы говорят вам о том, что вам нужно сделать, но для новичков в Rails, как и для меня, может быть непонятно, как собрать все эти вещи вместе, так что вот полное решение, включая обе миграции.и Модели.

Также, как примечание: я предпочитаю Займы, Кредитора и Заемщика, а не Расход, Кредитор и Должник, или Долг, Кредитор и Должник.Главным образом потому, что Расходы неоднозначны, а Долг слишком похож на Должника.Но это не , что важно;просто делайте то, что имеет для вас смысл, поскольку вы будете поддерживать свой код.

Миграции

class CreateLoans < ActiveRecord::Migration
  create_table :loans do |t|
    def up
      t.references :lender
      t.references :borrower
    end
  end
end

Здесь вы указываете, что в этой таблице есть два столбца, которые будут называться: кредитор и: заемщик и которые содержат ссылки на другую таблицу.Rails фактически создаст для вас столбцы с именами lender_id и loaner_id.В нашем случае они будут ссылаться на строки в таблице Users, но мы указываем это в моделях, а не в миграциях.

Models

class Loan < ActiveRecord::Base
  belongs_to :lender, class_name => 'User'
  belongs_to :borrower, class_name => 'User'
end

Здесь вы создаете свойство для модели ссуды с именем: lender, а затем указываете, что это свойство связано с классом User.Rails, увидев «own_to», будет искать столбец в таблице ссуд под названием «lender_id», который мы определили выше, и использовать его для хранения внешнего ключа.Затем вы делаете то же самое для заемщика.

Это позволит вам получить доступ к вашему Кредитору и Заемщику, оба экземпляра модели User, через экземпляр модели Loan, например:

@loan.lender # Returns an instance of the User model
@loan.borrower.first_name # Returns a string, as you would expect

В качестве дополнительного примечания: номенклатура «принадлежат к» имеет приличный смысл в этом случае, но может привести к путанице в другом месте.Просто помните, что он всегда используется в зависимости от того, что содержит внешний ключ.

class User < ActiveRecord::Base
  has_many :loans_as_lender, :class_name => 'Loan', :foreign_key => 'lender_id'
  has_many :loans_as_borrower, :class_name => 'Loan', :foreign_key => 'borrower_id'
end

Здесь вы создаете свойство для модели User с именем: loan_as_lender, указывая, что это свойство связано с моделью Loan, ичто внешний ключ в модели Loan, который связывает его с этим свойством, называется lender_id.Затем вы делаете то же самое для: loan_as_borrower.

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

@address.loans_as_lender
@address.loans_as_borrower

Выполнение любого из этихвернет массив экземпляров модели Loan.

1 голос
/ 07 февраля 2012

Если миграция ваших расходов выглядит следующим образом:

create_table :expenses do |t|
  t.integer :creditor_id, :null => false
  t.integer :debtor_id, :null => false
  # other attributes here
end

, тогда вам достаточно модели расходов.Если вы посмотрите на документацию для принадлежащих_ к , вы увидите, что она правильно выведет внешние ключи в таблицу пользователя:

: foreign_key

Укажите внешний ключ, используемый для ассоциации.По умолчанию это имя ассоциации с суффиксом _id.Таким образом, класс, который определяет ассоциацию own_to: person, будет использовать «person_id» в качестве значения по умолчанию: foreign_key.Точно так же, own_to: favourite_person,: class_name => "Person" будет использовать внешний ключ "fav__person_id".

Так что вам не нужно явно указывать здесь внешний ключ.Если вы используете другие соглашения об именах для идентификаторов в своей модели расходов, то вам необходимо явно указать их в своих ассоциациях.

Для вашей модели User вы не имеете отношения many_to_many с расходами - расходы всегдапринадлежит ровно одному должнику и ровно одному кредитору.Так что все, что вам нужно, это две has_many ассоциации:

has_many :debts,  :class_name => 'Expense', :foreign_key => :debtor_id
has_many :credits :class_name => 'Expense', :foregin_key => :creditor_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...