blocking task to a child Thread The main thread can do some other heavy tasks I know the reality is not that simple For example, in many cases, you will be caching some results in the client side. In such case, you need to synchronize the threads before caching But anyway, think about using threads. This is the basic idea
a background Thread. Joins at #records call AR::Relation#future # e.g. @posts = current_user.posts.future # Runs the block in a background Thread, checking out a new AR connection and releasing it. Returns a Future object FutureRecords.future(&block)
comments But it works Actually, it's already used in our production app at Money Forward Please be careful not to exhaust all the connections in the connection pool
of make this work locally, but it required super crazy monkey-patches on AR::Relation, FinderMethods, connection adapters, etc. Also, maybe we need to create another connection pool instance that handles async connections There's an existing library for doing this. Check out em-synchrony project if you're interested in this approach I personally don't want my production Rails app to heavily depend on EM though
this is not really a good approach Because the partial needs an extra routes and a controller. It’s like creating a whole set of API for just a partial template It adds another huge overhead for Ajax roundtrip, especially on narrowband
ActionView::OutputBuffer < ActiveSupport::SafeBuffer < String You need to make sure that the value is_a String before <<ing Otherwise, it may cause an error, or an unexpected result
[] end def <<(value) @values << value unless value.nil? self end alias :append= :<< def to_s @values.join # or something like that end ... end ActionView::OutputBuffer.prepend AsyncPartial::ArrayBuffer
the current String-based OutputBuffer There's an implementation that is faster than Erubi, or Haml, or any other existing template engine in the world The gems is called string_template
used to render the block content inside <%= ... do %> capture creates a new buffer, swaps @output_buffer ivar, then swaps it back at the end It's impossible to do such thing for a lvar
a lot of monkey-patches But, this works only with Erubi so far We have so many other template engines, such as Erubis, Haml, Slim, etc. Especially, monkey-patching Haml is so tough (Even for the main maintainer of Haml...!)
i, col2: i, col3: i, col4: i, col5: i, col6: i, col7: i, col8: i, col9: i, col10: i, col11: i, col12: i, col13: i, col14: i, col15: i, col16: i, col17: i, col18: i, col19: i, col20: i, col21: i, col22: i, col23: i, col24: i, col25: i, col26: i, col27: i, col28: i, col29: i, col30: i, col31: i, col32: i, col33: i, col34: i, col35: i, col36: i, col37: i, col38: i, col39: i, col40: i, col41: i, col42: i, col43: i, col44: i, col45: i, col46: i, col47: i, col48: i, col49: i, col50: i, col51: i, col52: i, col53: i, col54: i, col55: i, col56: i, col57: i, col58: i, col59: i, col60: i, col61: i, col62: i, col63: i, col64: i, col65: i, col66: i, col67: i, col68: i, col69: i, col70: i, col71: i, col72: i, col73: i, col74: i, col75: i, col76: i, col77: i, col78: i, col79: i, col80: i, col81: i, col82: i, col83: i, col84: i, col85: i, col86: i, col87: i, col88: i, col89: i, col90: i, col91: i, col92: i, col93: i, col94: i, col95: i, col96: i, col97: i }'
Work What we really need here in this situation is just a value object (something like "entity bean" in the Java world) AR model is apparently an overkill for this usage AR object has too many features such as type casting, dirty tracking, serialization, validation, etcetc.
the Example in This Slides But we don't want to do that in Ruby. Ruby is not Java. And we want to use associations, some other methods defined on the model class, etc. And it won't play nice with our favorite decorator plugin
objects work speedily by default? It's great that AR has a lot of elegant features, but we want the model instances to perform as fast as possible by default
an Instance from DB Query Result module LightweightAttributes class AttributeSet class Builder ... def build_from_database(values = {}, _additional_types = {}) LightweightAttributes::AttributeSet.new values ennnnd
def attributes_builder # If the model has no custom attribute if attributes_to_define_after_schema_loads.empty? LightweightAttributes::AttributeSet::Builder.new(...) else super ennnd
in your app, consider doing them in child threads You can run AR queries in Threads, but be careful not to use up all pooled connections ActionView::OutputBuffer can be Array based, for some future extensions Monkey-patching Haml is hard LazyAttribute is so lazy, and opting this out may drastically boost the performance url_for is slow, and we need to fix it
All these plugins are experimental. They basically have no tests, no documentations, no comments at the moment Put them in actual production apps I'm sorry but the title of this talk was probably a little bit misleading Introduce more extensibility to the framework I realized some things that should better be changed in the framework side rather than in monkey-patch plugins