问题
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).
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;
Could someone provide some direction as to how to properly form this ActiveRecord association?
Update:
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
回答1:
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
.
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
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
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
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
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 maintains its own understanding of VendorPass
which is "it's a Pass
, whose type
is VendorPass
", same with FacultyPass
.
The good parts:
- Easy to imagine: data structure seems sane and logical
- We're free to add more types of
Pass
es without changing the database
The bad parts:
- 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
回答2:
Let's say that every event has a ticket which is unique to an individual, an event and says whether the person is being admitted as a faculty member or vendor.
class User < ActiveRecord::Base
has_many :tickets
has_many :events, through: :tickets
end
class Event < ActiveRecord::Base
has_many :tickets
has_many :users, through: :tickets
end
class Ticket < ActiveRecord::Base
belongs_to :event
belongs_to :user
belongs_to :vendor
belongs_to :faculty
end
class Faculty < ActiveRecord::Base
has_many :tickets
end
class Vendor < ActiveRecord::Base
has_many :tickets
end
来源:https://stackoverflow.com/questions/25574745/i-need-help-properly-forming-this-activerecord-association