Open mosaaleb opened 1 month ago
Hey @mosaaleb, thanks for opening an issue with us! I think this happens because the block passed to with_ransacker
isn't called until the ransacker
slot is rendered. I don't know if there's a way to figure this out so that we can raise or warn if folks try to access slots in advance of that, but it might be a good thing to add if we can.
This behaviour isn't obvious, but I think it could signal some changes you may want to make to your components.
Looking at this, I would expect that this code indicates the hierarchy of components here:
<%= render ToolbarComponent.new do |toolbar| %>
<% toolbar.with_ransacker(query: query, url: url) do |ransacker| %>
<% ransacker.with_filter(field: field, select_options: []) %>
<% end %>
<% end %>
That is, I'd expect the template for ToolbarComponent
to render RansackerComponent
, and I'd expect the template for RansackerComponent
to be rendering FilterComponent
s. In this code:
# toolbar_component.html.erb
<%= ransacker if ransacker? %> <!-- order 1 -->
<% if ransacker&.filters? %> <!-- order 2 -->
<div class="flex gap-4">
<% ransacker.filters.each do |filter| %>
<%= filter %>
<% end %>
</div>
<% end %>
...ToolbarComponent
is reaching down into the RansackerComponent
's FilterComponent
s to render them. So I would first consider the structure of these components – if ToolbarComponent
needs to do something based on the filter
s, perhaps consider passing them into it as data and then using said data in a lambda slot, e.g.:
# ToolbarComponent.new([{ field: field, select_options: []}, {...}])
class ToolbarComponent < ApplicationComponent
def initialize(filters)
@filters = filters
end
renders_one :ransacker, lambda do |**kwargs|
RansackerComponent.new(**kwargs)
.tap do |c|
@filters.each { |filter_args| c.with_filter(**filter_args) }
end
end
end
end
@mosaaleb does the above work for you or is it still an issue
I have a ToolbarComponent that renders a single RansackerComponent, and the RansackerComponent renders multiple FilterComponent slots. Here's a simplified version of the setup:
In the view, the components are used like this:
And the ToolbarComponent template looks like this:
The ransacker component renders a ransack search form, and the rendering of the filters is delegated to be rendered within the toolbar component.
Problem
If I swap the order of the components (i.e., checking for ransacker.filters? before rendering ransacker), nothing gets rendered at all.
Questions
Steps to reproduce
Expected behavior
The ToolbarComponent should conditionally render the RansackerComponent and its FilterComponent slots. When the order of checking and rendering components is swapped, the components should still be rendered correctly.
Actual behavior
When the order of checking for ransacker.filters? and rendering ransacker is swapped, nothing gets rendered at all. It seems that the conditional checks on slots like ransacker&.filters? might not be working as expected.
System configuration
Rails version: 7.0.4 Ruby version: 3.1.0 Gem version: 3.0.0
Any insights or recommendations would be greatly appreciated!