So I have a 'ThaaliTakhmeens
' controller where some actions have their corresponding turbo_stream
templates to lazy load instances from databases using hotwire with pagination (pagy). And in those actions, there's a similar logic that I want to factor out into an after_action
callback, (following the DRY principle).
After factoring out the code into an after_action
, the instances don't show up on the page in fact the after_action
doesn't get executed at all which I verified by giving the debugger
in it. I have also provided a before_action
to those actions which works perfectly fine.
Here's the code:
after_action :set_pagy_thaalis_total, only: [:complete, :pending, :all]
def complete
@tt = ThaaliTakhmeen.includes(:sabeel).completed_year(@year)
end
def pending
@tt = ThaaliTakhmeen.includes(:sabeel).pending_year(@year)
end
def all
@tt = ThaaliTakhmeen.includes(:sabeel).in_the_year(@year)
end
private
def set_pagy_thaalis_total
@total = @tt.count
@pagy, @thaalis = pagy_countless(@tt, items: 8)
debugger
end
Here's the log on visiting the 'complete
' action:
Started GET "/takhmeens/2022/complete" for ::1 at 2023-01-21 10:07:35 0530
Processing by ThaaliTakhmeensController#complete as HTML
Parameters: {"year"=>"2022"}
Rendering layout layouts/application.html.erb
Rendering thaali_takhmeens/complete.html.erb within layouts/application
Rendered shared/_results.html.erb (Duration: 2.4ms | Allocations: 2088)
Rendered thaali_takhmeens/complete.html.erb within layouts/application (Duration: 3.7ms | Allocations: 2396)
Rendered layout layouts/application.html.erb (Duration: 3.9ms | Allocations: 2477)
Completed 500 Internal Server Error in 6ms (ActiveRecord: 0.0ms | Allocations: 3027)
ActionView::Template::Error (undefined method `any?' for nil:NilClass
'.freeze; if instances.any?
^^^^^):
1: <%= turbo_frame_tag :results, data: { turbo_action: "advance" } do %>
2: <div >
3: <% if instances.any? %>
4: <%= render partial: "theader" %>
5: <div id=<%="#{id}"%> ></div>
6: <%= turbo_frame_tag :pagination, loading: :lazy, src: path %> %>
app/views/shared/_results.html.erb:3
app/views/shared/_results.html.erb:1
app/views/thaali_takhmeens/complete.html.erb:8
Since the after_action
callback doesn't run, the instances
(@thaalis
) object is not set hence this error shows up, and also debugger
didn't get executed either.
Here the complete
action has both HTML
and turbo_steam
templates. And just to be clear that the content loads perfectly fine without the need for an after_action
callback but that would be against the DRY principle.
So what would be the workaround for this? Is there another way to refactor the code or should I have to set something explicitly in the callback method to get it executed?
CodePudding user response:
Good question. I actually not use after_action often and had to check. https://guides.rubyonrails.org/action_controller_overview.html#after-filters-and-around-filters What I think happen is that the rendering of the view is part of the action.
In your case this is inferred, you have no respond to block like this:
respond_to do |format|
if @record.update(record_params)
format.html { redirect_to a_record_route }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
But the rendering of the template still happens in the action. Before you set some instance variables useful to the view.
What you can do if you really want to dry up your controller is adding set_pagy_thaalis_total
at the end of each of your actions and removing the after_action.
EDIt: Also the fact your view is an html.erb or turbo_stream.erb file doesn't really matter.