클래식 연결에 대한 대안이 실패합니다.
Everything in our knowledge... contains nothing but mere relations —Kant
이 포스트에서 나는 다른 모델 간의 관계를 위한 테이블/모델과 같은 간단한 아이디어가 어떻게 더 행복한 개발을 만드는지 보여줄 것입니다.
핵심 교리는 다음과 같습니다.
연관이 필요한 두 모델이 엄격한 부모-자식 커플링이 아닌 경우 항상 연결 모델을 사용합니다. Order와 OrderItem은 상위 주문이 없는 항목이 존재하지 않기 때문에 엄격한 결합인 반면, 일부 사용자와 프로젝트는 서로 없이 존재할 수 있기 때문에 강력하게 결합되지 않습니다.
사례1, 남자친구와 여자친구
나는 이것을 일부 SO 토론에서 보았을 것이라고 맹세합니다. 예는 고안된 것일 수 있지만 목적에 도움이 될 것입니다.
소셜 앱을 만들고 Boyfriend 모델을 가지고 있고
has_one :girlfriend
를 도입할 생각을 하고 있다고 가정합니다. 이렇게 하려면 가능한 여자 친구 모델에 boyfriend_id
열이 있어야 합니다.# bad
class Boyfriend
has_one :girlfriend
# Table name: boyfriends
#
# id :integer(11) not null, primary key
end
class Girlfriend
belongs_to :boyfriend
# Table name: boyfriends
#
# id :integer(11) not null, primary key
# boyfriend_id :integer(11) not null
end
이 모델링에는 적어도 두 가지 문제가 있습니다. 왜 남자친구는 여자친구 한 명에게만 제한되어 있습니까? 그리고 왜 여자친구가 남자친구에게 속한다는 성차별적 암시가 있습니까?
두 신조를 모두 준수하면 남자 친구와 여자 친구 모두 실제로는 자신의 사람이며 그들의 관계는 완전히 다른 것임을 알 수 있습니다.
# good
class Person
enum gender: {female: 0, male: 1, other: 2}
has_many :relationships, foreign_key: :of_person
_id
# bonus
has_many(
:boyfriends, -> { where(gender: "male") },
through: :relationships, source: :with_person
)
has_many(
:girlfriends, -> { where(gender: "female") },
through: :relationships, source: :with_person
)
# Table name: people
#
# id :integer(11) not null, primary key
# gender :integer(11) not null, default: 0
end
class Relationship
belongs_to :of_person
belongs_to :with_person
# Table name: relationships
#
# id :integer(11) not null, primary key
# of_person_id :integer(11) not null
# with_person_id :integer(11) not null
end
이 "지시된"또는 "유형화된"관계 모델링에는 두 개의 레코드가 필요합니다. 하나는 "남자친구"에 대한 것이고 다른 하나는 관계의 "여자친구"에 대한 것입니다. 모든 성별 페어링을 수용할 수 있으며 가족 관계에도 다양한 타이핑이 가능합니다.
Case2, 계정의 기본 사용자
this SO question 에서 영감을 받았습니다.
사용자가 많을 수 있는 계정이 있으며(일종의 은행 업무, 마케팅 등 비즈니스 계약?) 이제 특별한 "기본"사용자가 있어야 하며, 이상적으로는 계정당 한 명이 필요합니다.
# bad
class Account
has_many :users
has_one :primary_user, -> { where(primary: true) }, class_name: "User"
# Table name: accounts
#
# id :integer(11) not null, primary key
end
class User
belongs_to :account
# Table name: users
#
# id :integer(11) not null, primary key
# email :string(200) not null, default ""
# account_id :integer(11) not null
# primary :boolean not null, default false
#
# indexes
# (account_id, primary) UNIQUE, WHERE(primary = true)
end
다시 말하지만, 두 가지 원칙을 모두 적용하면 사용자가 계정에 대한 엄격한 "자식"개체가 아닐 수 있으므로 계정과의 관계는 별도의 모델이 필요합니다. 또한, 우선 순위는 "계정-사용자"관계와 계정 간의 특별한 종류의 관계이기도 합니다.
# good
class Account
has_many :account_users
has_one :primary_user
# Table name: accounts
#
# id :integer(11) not null, primary key
end
class User
has_one :account_user
has_one :account, through: :account_user
# Table name: users
#
# id :integer(11) not null, primary key
# email :string(200) not null, default ""
end
class AccountUser
# Tie model, which account a user is part of.
belongs_to :account
belongs_to :user
# Table name: account_users
#
# id :integer(11) not null, primary key
# account_id :integer(11) not null
# user_id :integer(11) not null
#
# indexes
# (user_id) UNIQUE # a user can only ever be in one account
end
class PrimaryAccountUser
# Stores which user is the primary user in an account.
# Note that belonging to :account_user instead of :user reduces the risk of the relationship being removed, but primacy remaining.
belongs_to :account_user
belongs_to :account
# Table name: account_users
#
# id :integer(11) not null, primary key
# account_id :integer(11) not null
# account_user_id :integer(11) not null
#
# indexes
# (account_id) UNIQUE # an account can only ever have one primary user
end
이 모델링을 통해 서로 의존하지 않는 계정과 사용자를 만들 수 있습니다. 사용자는 AccountUser 레코드를 만들어 계정과 연결할 수 있으며, 마지막으로 PrimaryAccountUser 레코드를 만들어 기본 사용자를 지정할 수 있습니다(사용자가 먼저 계정과 연결된 경우).
Reference
이 문제에 관하여(클래식 연결에 대한 대안이 실패합니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/epigene/alternatives-to-classic-association-fails-44lk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)