I need help properly forming this ActiveRecord association

二次信任 提交于 2019-12-17 21:37:08

问题


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 Passes 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 a string, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!