Home > Mobile >  Unable to run after_action callback for turbo_stream actions
Unable to run after_action callback for turbo_stream actions

Time:01-21

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.

  • Related