我需要帮助正确形成这个 ActiveRecord 关联 [英] I need help properly forming this ActiveRecord association
问题描述
基本上,用户可以作为(或可能同时作为)供应商和活动教职员工参加一个或多个活动.
Basically, a User can participate in one or more events as either (or potentially both) a vendor and as a member of the event's faculty.
默认情况下,用户既不归类为供应商也不归类为教职员工,而是在事件上下文中获得任一(或两者)状态(例如,用户已被允许参加事件作为其教职员工).
A user is, by default, categorized as neither a vendor nor a faculty member but rather attains either (or both) status(es) within the context of an event (e.g., the user has been admitted to an event as a member of its faculty).
似乎我想说的是,用户通过供应商或教师链接表(或两者)有许多事件,但我不确定我是否会在我的 Rails 模型中表示这一点.这是我迄今为止尝试过的:
It seems like what I want to say is that the user has many events through either (or both) the vendors or the faculty linking tables, but I'm not sure I'd go about representing this in my Rails model. Here's what I've tried so far:
class User < ActiveRecord::Base
has_many :events through => vendors
has_many :events through => faculty
end
以下是我认为需要执行的查询示例:
Here's a sample of a query that I think I'd need to make:
Select * from vendors where user_id = 1;
Select * from faculty where user_id = 1;
有人可以就如何正确形成此 ActiveRecord 关联提供一些指导吗?
Could someone provide some direction as to how to properly form this ActiveRecord association?
更新:
因此,我已尝试使用单表继承来解决该问题,但最终得到了一个仅包含单个用户类型记录的用户表.在仍然使用单表继承的同时,如何让我的用户拥有多种类型?(我知道这本质上是一种多对多的关系;我只是不确定如何使用 STI 来实现这一点.)
So, I've tried using single-table inheritance to solve the issue, and I've ended up with a user table which records containing only a single user type. While still using single-table inheritance, how do I get my users to have multiple types? (I know this is essentially a many-to-many relationship; I'm just not sure of how to accomplish this using STI.)
id | first_name | last_name | birth_date | city | zip_code | email | type | created_at | updated_at
----+------------+-----------+------------+------+----------+-------+---------+----------------------------+----------------------------
1 | Akira | Yamaoka | | | | | Vendor | 2014-08-30 14:58:26.917333 | 2014-08-30 14:58:26.917333
2 | Pyramid | Head | | | | | Faculty | 2014-08-30 15:02:04.70209 | 2014-08-30 15:02:04.70209
推荐答案
单表继承可能正是您所需要的.简而言之:它允许将具有相同类型数据的多个类放入一个表中.唯一的要求是该表有一个 type
列,一个 string
.
Single-table inheritance might be what you need. In a nutshell: it allows several classes with the same kind of data to be put into one table. The only requirement is that that table has a type
column, a string
.
基本上,这是关于常识.比方说,用户可以拥有参加活动的通行证:供应商通行证和教职员工通行证.他可能两者兼而有之.让我们创建一个 Pass
模型,记住我们需要不同种类的它.但是我们稍后会使用它.现在让我们坚持使用 has_many through
:
Basically, it's about common sense. Let's say, a user can have passes to an event: a vendor's pass and a faculty member's pass. He might have both. Let's create a Pass
model, bearing in mind that we'll need different kinds of it. But we'll use it later. For now let's just stick to has_many through
:
rails g model Pass type:string user:references event:references
迁移这个,我们就不需要再修改我们的数据库了.我们只会修改 Ruby.我们应该有一个Pass
类,我们需要在关联中标记它的角色:
Migrate this and we won't need to modify our database anymore. We'll only modify Ruby. We should have got a class Pass
, we'll need to mark its role in association:
class Pass < ActiveRecord::Base
belongs_to :user
belongs_to :event
end
好吧.然后我们会有这样的 User
和 Event
:
All right. Then we'll have this sort of User
and Event
:
class Event < ActiveRecord::Base
has_many :passes
has_many :users, through: :passes
end
class User < ActiveRecord::Base
has_many :passes
has_many :events, through: :passes
end
这就是 STI 魔法的由来.让我们再创建两个类.
Here's where the STI magic comes. Let's create two more classes.
rails g model VendorPass --no-migration --parent=Pass
rails g model FacultyPass --no-migration --parent=Pass
我们生成了一些没有数据库表的类(我们不需要它们).它们是空的,我们不会改变它:它们继承了一个 Pass
而这就是我们所需要的.但是我们需要在我们的 User
、Event
和新通行证之间创建一些额外的关联.最后,我发现这行得通:
We've generated some classes without database tables (we don't need them). They are empty and we won't change it: they inherit a Pass
and that's all we need. But we'll need to create some extra associations between our User
, Event
and the new passes. In the end, I've found this working:
class Event < ActiveRecord::Base
# We already had this
has_many :passes
has_many :users, through: :passes
# New stuff!
has_many :vendor_passes
has_many :vendors, through: :vendor_passes, source: :user
has_many :faculty_passes
has_many :faculty_members, through: :faculty_passes, source: :user
end
class User < ActiveRecord::Base
# We already had this
has_many :passes
has_many :events, through: :passes
# New stuff!
has_many :vendor_passes
has_many :vendor_events, through: :vendor_passes, source: :event
has_many :faculty_passes
has_many :faculty_events, through: :faculty_passes, source: :event
end
Rails 保持自己对 VendorPass
的理解,即它是一个 Pass
,其 type
是 VendorPass
", 与 FacultyPass
相同.
Rails maintains its own understanding of VendorPass
which is "it's a Pass
, whose type
is VendorPass
", same with FacultyPass
.
好的部分:
- 容易想象:数据结构看起来合理且合乎逻辑
- 我们可以自由添加更多类型的
Pass
es而无需更改数据库
- Easy to imagine: data structure seems sane and logical
- We're free to add more types of
Pass
es without changing the database
不好的部分:
- 无法仅向
Pass
的特定子类添加额外字段:它们都在同一个表中 - 关联看起来有点重复和繁琐
- Rails 只允许
type
为string
,而不是最快的比较类型
- No way to add extra fields to only specific subclasses of
Pass
: they're all in the same table - Associations look a bit repetitive and cumbersome
- Rails only allows
type
to be astring
, not the fastest type to compare
这篇关于我需要帮助正确形成这个 ActiveRecord 关联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!