1

Let's say you run a content site for cartoon artists. Cartoon artists create a lot of resources: Drawings, Articles, Magazines, Books, Schemas, Projects, Courses, Lectures etc. Those resources have similar attributes, like title, year, etc. but each also has it's own attributes like issue for Magazines and isbn for books, so we end up with 13 different models but similar in a sense.

One day we build an aggregation site where we list all the resources on 1 page that displays the right attributes dynamically for each resource in each row of the list. For that we get our resources in one Collection in our resources controller:

# RessourcesController
def index
  @resources = get_resources
end

And try to display it in a list in our view:

# app/views/ressources/index.html.erb
<% @ressources.each do |ressource| %>
  <div class="list">
    Title: <%= ressource.title %>
    Year: <%= ressource.year %>
    <%= "Book: #{ressource.isbn}" if ressource.class == Book %>
  
    # ... much more nasty case handling ...
  </div>
<% end %>

This gets pretty dark and unreadable pretty quickly. So, I've thought about having a partial for each ressource (and maybe a partial for the common attributes) and using a helper that would decide which partial to load based on the class:

# ressource_display_helper.rb
def display(ressource)
  case ressource
  when Book
    render "book"
  when Magazine
    render "magazine"

  # ... many more ...
  
  else
    # Render nothing for unknown ressource
  end
end

So the view becomes:

# app/views/ressources/index.html.erb
<% @ressources.each do |ressource| %>
  render "common_attributes"
  display(ressource)
<% end %>

Is there a better pattern to build an aggregated list like this or is a helper a good choice to move the decision logic out?

How would you decide whether to use 13 different models, duplicating like 6 attributes per model (remember title, year etc.), vs having an abstract Ressource model and then go with Single Table Inheritance? Looking at this answer: What to consider when deciding to use Single Table Inheritance

It matches 1 criteria: Do you need to do database queries on all objects together? But only on 1 page where we display the list of all ressources. So probably for simplicity's sake and as long as we don't hit performance issues, it's fine to use 13 different models.

Rich Steinmetz
  • 1,020
  • 13
  • 28
  • Does get_resources return an array with everything inside? – kouroubel Apr 30 '22 at 13:14
  • You don't need to write a helper. Rails will actually automatically handle rendering the right partial when you pass a non-homogenious collection to `render`. It does it by calling `.to_model.model_name` on each record. https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections – max Apr 30 '22 at 16:33
  • In this case it would look for `books/_book.html.erb` and `magazines/_magazine.html.erb`. – max Apr 30 '22 at 16:37
  • @kouroubel could be an Array but could also be an ActiverRecord::Association type of thing. Not really bound to any of them so far. – Rich Steinmetz Apr 30 '22 at 19:39
  • Oh, that's a great insight @max didn't know about that magic part. That'd make things actually a lot easier. If you like to answer the question, I'll accept that one as the better solution for this. I guess keeping it without an STI is also a fine thing to do in this scenario. – Rich Steinmetz Apr 30 '22 at 19:41
  • This is magic indeed!!! – kouroubel Apr 30 '22 at 20:57

0 Answers0