Idea #2871
Updated by Tom Clegg over 10 years ago
Example pages
* Show new/ready pipeline instance with lots of collections in script_parameters (e.g., GATK exome pipeline): this currently does multiple API lookups for each "select a collection" drop-down.
* Dashboard has a similar problem
* "Metadata" tab on a "show" page does multiple API lookups for each link it displays
Approach
* For a common type of lookup like "links pointing to X", create helper methods in ApplicationController to handle preloading and on-demand lookups.
<pre><code class="ruby">
helper_method :links_for_object
def links_for_object object_or_uuid
uuid = object_or_uuid.is_a?(String) ? object_or_uuid : object_or_uuid.uuid
preload_links_for_objects([uuid])
@all_links_for[uuid]
end
helper_method :preload_links_for_object
def preload_links_for_objects objects_and_uuids
uuids = objects_and_uuids.collect { |x| x.is_a?(String) ? x : x.uuid }
@all_links_for ||= {}
if not uuids.select { |x| @all_links_for[x].nil? }.any?
# already preloaded for all of these uuids
return
end
uuids.each do |x|
@all_links_for[x] = []
end
# TODO: make sure we get every page of results from API server
Link.filter([['head_uuid','in',uuids]]).each do |link|
@all_links_for[link.head_uuid] << link
end
end
</code></pre>
In any controller/helper/view, when you expect to be looking up links for a set of objects:
<pre><code class="ruby">
preload_links_for_objects @objects
</code></pre>
In any controller/helper/view when you need a list of links referencing a given object, instead of doing Link.where(), do:
<pre><code class="ruby">
links_for_object(@object).each do |link|
if link.link_class == 'name'
# do stuff with link.name
end
end
</code></pre>
This will at least avoid doing multiple lookups for the same collection ID when rendering N select widgets, etc. Judicious use of "preload" will reduce round-trips further: e.g., combine all of the name/tag lookups for collections#index list into one API call by doing @preload_links_for_objects(@objects)@.