Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fragment caching within component not working #105

Closed
davidalejandroaguilar opened this issue Sep 1, 2023 · 4 comments
Closed

Fragment caching within component not working #105

davidalejandroaguilar opened this issue Sep 1, 2023 · 4 comments

Comments

@davidalejandroaguilar
Copy link
Contributor

davidalejandroaguilar commented Sep 1, 2023

Expected result:

The component is fragment cached.

Actual result:

NoMethodError (undefined method `length' for nil:NilClass

        pos = output_buffer.length
                           ^^^^^^^):
  
app/views/components/test_component.rb:3:in `template'
app/controllers/tests_controller.rb:3:in `index'

How to reproduce:

  1. Enable dev caching
rails dev:cache
  1. Add a component
class TestComponent < ApplicationComponent
  def template
    helpers.cache do # Note that there's no Cache Phlex helper.
      plain "hi"
    end
  end
end
  1. Render it
class TestsController < ApplicationController
  def index
    render TestComponent.new
  end
end

Notes

  1. There's also no Cache Phlex helper for Rails.
  2. I did some digging and found this:
@davidalejandroaguilar davidalejandroaguilar changed the title Fragment caching not working Fragment caching within component not working Sep 1, 2023
@joeldrapper
Copy link
Collaborator

Hey @davidalejandroaguilar, unfortunately Phlex doesn't support fragment caching, but it's fast enough that you shouldn't need it.

Instead, you can use "low-level caching" to cache your database queries and then render the views fresh.

@davidalejandroaguilar
Copy link
Contributor Author

Thanks for responding @joeldrapper, I'm mostly interested in avoiding db queries, rather than view rendering.

Usually, there are many database calls being done within a view. e.g. if you render a Orders::ShowView.new(order:), maybe within that view you'd have order.payments.any? or order.order_items.any?.

Are you suggesting to wrap every single one of those db calls within a Rails.cache? e.g. by extracting those to methods such as any_payments? or any_order_items?, e.g.

def any_payments?
  Rails.cache.fetch(order) do
    order.payments.any?
  end
end

That might be a bit cumbersome, but doable.

Also, as noted in the issues I linked, seems like fragment caching was supported and was removed since "compiled components" would make them unnecessary. Why was that? Just curious.

@davidalejandroaguilar
Copy link
Contributor Author

@joeldrapper Or do you think we should rather always wrap a Phlex component inside a Rails partial if fragment caching is desired, once #106 is fixed? e.g.

show.html.erb

<%= cache [some, objects] do %> 
  <%= render "my_component_wrapper" %>
<% end %>

my_component_wrapper.html.erb

<%= render MyComponent.new(some:, objects:)  %>

my_component.rb

class MyComponent < ApplicationComponent
  def initialize(some:, objects:)
    # ...
  end
  
  def template
    # ... use objects
  end
end

@joeldrapper
Copy link
Collaborator

Personally, I don’t think the cache is worth it. I would write all my queries in the controller, using strict loading and load async and wouldn't use a cache at all.

As long as you don't have N+1s (which you can't do if you use strict loading), the database should be fast enough. The view layer is definitely fast enough using Phlex, and you can render parts of the view while querying the database concurrently if you use load_async.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants