← Back to Upcase

DB Design - STI or Polymorphic?


(David Lee) #1

I’m redesigning the database I have for a Apartment Rental app. Currently, I have just one model for Users which includes both Apartment Seekers and Landlords. I recall in the Intermediate RoR video #2 that STI is appropriate for when the same objects share similar data, but have different behavior. In the workshop, we ended up using a polymorphic relationship for the TextShout and Photoshout (different data, but similar behavior (at least for now)).

My current setup is a little messy since the two types of users have both different data and behavior. What’s the best way to approach this? Thanks!


(Ben Orenstein) #2

It’s tough to offer much advice without more info. My answer would depend on how similar Apartment Seekers and Landlords are.

My hunch is that the answer is “not very”, so I’d go with two different models. I’d probably create a has_one :user relationship for both.

That way you separate the similarities of User (an entity that logs into the system), from their other data and behavior (Landlords likely have_many :properties , but Apartment Seekers don’t, for example).


(David Lee) #3

Based on the above, would it look something like this?

class User < ActiveRecord::Base
  #???
end

class Seeker < ActiveRecord::Base
  has_one :user
end

class Landlord < ActiveRecord::Base
  has_one :user
  has_many :listings
end

Apartment Seekers and Landlords share certain properties (email, password, facebook uid, etc.) and behavior (sign-in/out, send messages, etc.).

Potentially the same user could be both a landlord and an apt seeker.

Apartment seekers have some different attributes (for example, they can indicate that they want to be included in a renter search so that other users can see that they are looking), but right now, the number of unique attributes is limited but could change.

The bigger thing is that they have different behaviors and currently, in the views, I just check if the user has listings to decide what to show whenever the need arises (which feels messy). Down the road, I’d like to have different funnels/flows for seekers and landlords.

The site is www.aptjoy.com (if you’re curious).


(Ben Orenstein) #4

The code you included is what I was thinking, yes.


(Erik Guzman) #5

I also like this approach also. I would think that you could separate the apt seeker and landlord flow by offering separate dashboards.

As a side note: I remember seeing your website a few weeks back after you viewed my linkedin profile, small world. Ill be doing some apartment hunting in the next 2 months or so but will be looking in the south bay area. Ill give you site a try and provide any potential feedback.


(Pedro Moreira) #6

Hi, guys,
I’ve been struggling with this a similar situation. I have three very different entities in a system (Customer, Promotor and Artist). Customers only need to log in to, well, make a purchase. Promotors can sign up as such and have very different fields (social media connections, sign ups remain pending for approval initially) and Artists connect through Soundcloud omniauth.

At this point, would I be better off creating completely different paths for signing up instead of forcing a generic User model to be elastic enough? Should I create something like “devise_for :promotors” and so on?


(Ben Orenstein) #7

I recommend you listen to your code.

If it feels like you’re trying to jam too much into User, you probably are.


(Pedro Moreira) #8

Guys, I ended up with a polymorphic solution. I’ve put the code in a private gist. Hope this can still be of help.

I’m writing a blog post describing the thinking behind this, if you think it can be of interest I’ll share the link in this thread.

Edit: Forgot to thank @derekprior for his description of using calls to super to replace callbacks, presented in this thread