【发布时间】:2020-05-09 02:22:20
【问题描述】:
我意识到这有点固执己见,因此特别询问这是否是每个代码约定的好主意。
示例场景
在图书馆中为Books 和Clients 之间的关系建模,假设根据图书馆规则,客户一次只能签出一本书。
让我感到复杂的是,客户只在给定的时间段内签出一本书,然后将其退回。所以这几乎就像,你不希望这种关系永远持续下去……在某个时候,客户免除了那本书的责任(例如,如果一本书在客户退回 2 年后损坏了,你不想打电话给过去的客户要求更换)。
尽管它是暂时的,但您仍然需要记录这种关系,以便您可以跟踪查看过一本书的客户的历史记录(因为下线,也许您确实想向过去的客户发送调查问卷供评论)。
换句话说,在我看来,有两种关联……一种是暂时的,一种是更持久的。
虽然我可以在技术上编写代码来完成这项工作,但这似乎是一种糟糕的做法(就像......直觉上我觉得这个问题的答案是肯定的......这不是一个好的做法)。但我想确认一下,如果是这样,还有什么其他解决方案可以解决这个问题(has_many :through 可能通过表具有某种...current_rental 属性?)
两个关联的样子
Association #1,临时关联,你想知道一本书是借给哪个客户的
Client has_one :book, foreign_key: "current_id"
Book belongs_to :current_client, class_name: "Client", foreign_key: "current_id"
这种关系非常有用,如果客户打电话说他们忘记了要从个人书架归还哪本书,您可以致电@client.book.title。
关联 #2,长期关联,您想知道一本书的历史(进一步假设客户的历史并不重要,如果这样做,这将更清楚地是 has_many :through 或 HABTM 关系)
Client belongs_to :checkout_book, class_name: "Book", foreign_key: "book_id"
Book has_many :clients, foreign_key: "book_id"
通过这种关系,您可以查看一本书的历史、有多少客户已将其签出到@book.clients.size,或者您可以通过电子邮件向他们发送电子邮件以进行调查@book.clients.map(&:email)。
然后,这种分离消除了混淆,例如需要更换书籍,调用 @book.clients.last 可能会检索到不正确的客户,因为预订是提前进行的,因此结帐不一定按顺序进行。不过,您可以@book.current_client 让合适的人跟进。
【问题讨论】:
-
考虑模型是Users M-M Books。然后,“当前书”只是唯一一本书(如果以后允许的话,可以是多本书)。这使数据库模型保持一致,而无需其他技巧。无论数据库映射如何,代码计算属性总是可以返回“单一”书。返回书籍可能会更新加入关系实体的属性,或者可能导致关系被完全删除。
-
但是您仍然需要一些其他属性才能确定该多对多关系中的状态
checked out对吗?我想这是看待它的一种方式。一种解决方案是拥有这样一个属性,而我的解决方案没有属性但使用关系 -
也许在这种情况下,您可能会质疑关系的完整性。客户真的只有一本书吗?客户可以拥有的书籍总量不应受到限制。一次的图书总量是您想要限制的。您可以将数组属性设置为客户端已签出的书籍的名称,从而将签出限制限制为该数组的长度。在这种情况下,客户甚至可以出租多本书,这是非常合理的。
-
@james 实际上,是的(假设加入关系不是暂时的——在这种情况下,仅存在表示已签出)。我喜欢使用可导出的值,例如签入和签出日期。这也将允许多个结帐历史等。
标签: ruby-on-rails activerecord associations