1

Suppose I have the following setup in my Rails4 app:

A Student has_many degrees, a Degree belongs_to a Student. I have a StudentPresenter and a DegreePresenter corresponding to both models as well. (Presenters as defined here)

I want to query the following:

student_ids = [1,2,3,4]
students = Student.where(id: student_ids).includes(:degrees)

But I want to have access to the Presenter methods for both Student and Degree.

How do I preload data with Presenters?

Rails 4.1.5

Paul
  • 10,381
  • 13
  • 48
  • 86
XML Slayer
  • 1,530
  • 14
  • 31

1 Answers1

1

The presenters in the blog post you linked to are just simple ruby objects that take a model as one of the arguments when creating a new presenter:

So to create the StudentPresenters:

students = Student.where(id: student_ids).includes(:degrees)
decorated_students = students.map { |s| StudentPresenter.new(s, view_context) }

Then you could add a method to StudentPresenter which returns decorated degrees;

class StudentPresenter < BasePresenter
  def degrees
    @model.degrees.map { |d| DegreePresenter.new(d, @view) } 
  end
end

Added

How this works with preloading? Since you are using includes

With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.

Rails should load both students table and degrees as soon as you do students.map.

max
  • 96,212
  • 14
  • 104
  • 165
  • What if we have a lot of records ? Wouldn't we run into a performance issue because of all those presenters objects containing consequent instance variable like a ActionView instance ? – Sumak Apr 20 '20 at 15:33
  • 1
    Ruby is pass by reference so each instance variable still points to the same view_context object. But yes if you are loading a large number of records into memory decorating them will use even more memory. The solution to that is to never load large amount of records into memory which is going to be a problem anyways when scaling. Make sure your queries have a limit and use paging. – max Apr 20 '20 at 15:42
  • So we have to consider when to decorate or not ? If we have a huge associated collection (ie. a Student has_many Lecture), wouldn't it be better to access low-level cached data directly inside models, instead of instantiating dozens of objects ? Thanks for you answers, it really makes presenters and ruby less fuzzy to me ! – Sumak Apr 20 '20 at 16:10
  • 1
    Yeah decorators can definitely add a lot of overhead if you have a complex tree of associations and you have to weigh if the benefits of code organization is really worth it. I like decorators as pattern - but a lot less IRL. – max Apr 20 '20 at 16:15