In my application I have a complex database structure. In order to generate the JSON response for a call, I need to get data from many joined tables.
I created a SQL query that fetched all the data I need (using rails’ includes). however, now that I have the result in my view, I can’t figure what is the right way to actually render it.
A simplified example, not my actual code: Let’s say I have Project that contains SubProjects that contain Tasks and that the query returns some nested structure of them all, filtered according to some logic.
class Project < ActiveRecord::Base
...
def with_sub_projects_visible_by(user)
includes(...complex join with sub projects and tasks...)
.where(...complex condition...)
end
end
In the controller I have something like this:
def show
@project_with_full_details = Project.find(params[:id]).with_sub_projects_visible_by(current_user)
end
Is there a way to write simple view code that will render a page that contains all the data from @project_with_full_details without calling the database again? From what I tried, simply calling @project_with_full_details.sub_projects doesn’t do the trick. It calls the database and gets me the full list of related sub_projects instead of the filtered one that should be contained in the query results.
(I’m using RABL for my view, since I’m rendering JSON, but it’s less important, ERB example will be totally fine)
ActiveRecord provides a preloader for associations which causes Rails to only load the objects from the database once (it also happens before the page is loaded).
For your example, it would probably look something like this:
That would at least give you the desired effect of only running the SQL once.
If your models look something like this:
Then perhaps you could define a method like
subprojects_for(user). Then you should be able to do something along these lines:The real magic should have happened in the preloader, though. I assume you’ve looked at the server logs to see that the SQL is being run more than once?