Skip to main content

Few Big Models or Many Smaller Namspaced models?

Rails • Asked by Rich Smith
97598e2e5acd70619c1e7a24af523a64
Anyone able to give suggestions on model design? I'm building an app to help small businesses get more reviews across the web. Concept is simple, user registers a business, and their businesses location(s). They then send emails to their clients that contain a direct link to their locations review site (google my business, facebook review page, yelp etc.) Models so far: Users, Businesses, Locations. Businesses have many locations. The end goal is there will be a review_request model (which keeps track of the review requests for each location sent to the businesses clients) and a review_sites model - which would contain info on the locations review site (example site_name:facebook, site_domain:https://facebook.com, location_page: facebook.com/business-id-here.

My question is, should I keep all review sites in one big ugly model? Or should I namespace them and give each specific review site its own model? example models/review_sites/google_site.rb?

Ce795239ba5dd2384fc2f88ffaff5451
Hey Rich,

The best advice for these types of questions will always depend upon what you want to do in the future with your app. Will you be treating Facebook, Google, etc reviews as mostly the same thing? Sure, you'll need to know the site and page the review was on, but will you have specific integrations with each site?

If they will stay mostly similar, then I'd keep it as a single model and just store the site like "google" "facebook" etc as a column and the url for the page. Then if you ever do need to add some more specific things you can just say "okay this is a google review, let's create a Google API client and sync any changes".

If you plan on having different functionality for each review type, then separate models make more sense. You can then add functionality that's unique to each site (maybe they have a lot of different attributes you want to store).

So it'll depend upon what you want to do going forward. You probably know that best since you're designing the product which means you'll probably have a better idea of which one will be most fitting with your product. 

97598e2e5acd70619c1e7a24af523a64
Thanks Chris! Yea I am leaning towards separate models just because eventually I would like to have each site have different functions and am limited by the different sites having different API options.

Do you think something like this would work?

  • User has_one business
  • Business has_many :locations
  • Location has_one :facebook_page, through => :review_sites
  • Location has_one :google_page, through => :review_sites
  • Location has_one :yelp_page, through => :review_sites
  • ReviewSite belongs_to :location, has_one :yelp_page, has_one :google_page, has_one :facebook_page
  • FacebookPage belongs_to :review_site
  • GooglePage belongs_to :review_site
  • YelpPage belongs_to :review_site

I'd prefer not having a messy models folder though, is something like [this](http://blog.hasmanythrough.com/2008/5/6/a-simple-alternative-to-namespaced-models) still an option in Rails 5.2?


Ce795239ba5dd2384fc2f88ffaff5451
Hey Rich,

I wouldn't worry too much about having a "messy" models folder. If you had 50 models, it might be a concern, but you don't currently have many and it's easy to move things around later.

What is the purpose of ReviewSite? It seems like an unnecessary model.

User
has_one :business

Business
belongs_to :user
has_many :locations
has_many :facebook_pages, through: :locations
has_many :google_pages, through: :locations
has_many :yelp_pages, through: :locations

Location
has_one :facebook_page
has_one :google_page
has_one :yelp_page
has_many :reviews

FacebookPage
belongs_to :location

GooglePage
belongs_to :location

YelpPage
belongs_to :location

Review
belongs_to :location
belongs_to :customer (or something)

ReviewRequest
belongs_to :customer
belongs_to :business (if you want to attach it to a business, could also be location)

As you can see here, the concept of a "page" seems repeated so you may still want to consider how truly separate they are.

Business
has_many :pages

Page
belongs_to :business
-
site ("google", "facebook", "yelp")
- url
- number_of_reviews
- average_rating
- extra_data (json column, can be fully unique to each site)

Then you could just write other Ruby classes for handling the unique API situations. For example, to get the correct API client, you'd do something like:

def client
  case site
  when "google"
    GoogleApi.new(token)
  when "facebook"
    FacebookApi.new(token)
  end
end

This would be a more generic way of approaching things. You can have a json column to store any data that's unique to each business instead of making separate models for each.

Personally I would probably take this approach with generic pages. I haven't seen anything that seems to prevent taking this approach. This is how I handle the different APIs for Hatchbox.io btw. Servers on Hatchbox are like Pages and Reviews in your app. Sure they may be on a different service, but I can still store the generic information I care about in a single table and just keep track of which service it is. Then I write Ruby classes to handle the specifics and store the data on the model. Unless the data is vastly different, you will probably be best off with the generic Page like I'm doing with Servers. You can have a json column to store your extra information that may be unique to each site. If there is a lot of unique information for each Page, then definitely split up the models.

97598e2e5acd70619c1e7a24af523a64
Oh man, having a separate column with json to handle anything unique (which there really shouldn't be much of, if any) is brilliant! Just having a PORO handle any api stuff is perfect. I think that's exactly the route I will take.

Thanks so much for your help Chris! I really appreciate it. 

One last question, when I'm building out forms, what would be the best way to have page-specific forms? Just create different views for specific pages?

Ce795239ba5dd2384fc2f88ffaff5451
🙌 You're welcome!

As for the forms, you can just set the site in a hidden field. @page = Page.new(site: "google") for example.

Remember that your controllers don't have to directly map to models so you could have a controller for Google, separate from your Facebook one, and so on. Then you can have views that are unique so that you can have different designs, instructions, etc for each one.

97598e2e5acd70619c1e7a24af523a64
... I never really thought about the fact that my controllers don't have to map directly to models :/  That makes perfect sense. I suppose I will do a generic Page controller, then site(yelp, facebook, google, etc.) specific when required. 

Thanks for all your help Chris!

Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 18,000+ developers who get early access to new screencasts, articles, guides, updates, and more.

By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

More of a social being? We're also on Twitter and YouTube.