You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Turbo Stream动作中after_action回调无法执行的解决方案求助

问题

我有一个ThaaliTakhmeens控制器,其中部分动作拥有对应的turbo_stream模板,通过Hotwire结合Pagy实现数据库实例的懒加载分页。为遵循DRY原则,我将这些动作中的重复逻辑抽取到after_action回调中,但该回调完全未执行(已通过debugger验证),导致页面无法渲染实例,还出现模板错误。

相关控制器代码:

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

访问complete动作时的日志:

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 class="container text-center mt-5">
    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

错误原因是after_action未执行,导致@thaalis(即模板中的instances)未被赋值。这些动作同时具备HTML和turbo_stream模板,若不使用回调直接在动作内编写逻辑,内容可正常加载,但会产生重复代码。请问有什么可行的解决方法?是否有其他代码重构方式,或需要在回调中设置特定内容使其执行?

解决方案

1. 改用before_action替代after_action

模板渲染发生在after_action之前,这是回调未生效的核心原因。把回调改成before_action,就能确保在动作执行后、模板渲染前完成分页逻辑的处理:

before_action :set_pagy_thaalis_total, only: [:complete, :pending, :all]

# 其余动作和私有方法代码不变

2. 提取共用逻辑到私有方法,动作内显式调用

如果不想依赖回调,可把分页逻辑封装成私有方法,在每个动作里直接调用,既保证逻辑复用,又避免回调时机问题:

def complete
    @tt = ThaaliTakhmeen.includes(:sabeel).completed_year(@year)
    set_pagy_thaalis_total
end

def pending
    @tt = ThaaliTakhmeen.includes(:sabeel).pending_year(@year)
    set_pagy_thaalis_total
end

def all
    @tt = ThaaliTakhmeen.includes(:sabeel).in_the_year(@year)
    set_pagy_thaalis_total
end

private

def set_pagy_thaalis_total
    @total = @tt.count
    @pagy, @thaalis = pagy_countless(@tt, items: 8)
end

3. 利用around_action(可选)

around_action可以包裹动作的执行过程,确保分页逻辑在模板渲染前完成,相对前两种方式稍复杂:

around_action :wrap_pagy_logic, only: [:complete, :pending, :all]

def complete
    @tt = ThaaliTakhmeen.includes(:sabeel).completed_year(@year)
end

# 其余动作代码不变

private

def wrap_pagy_logic
    yield # 先执行动作代码
    set_pagy_thaalis_total # 动作执行完后处理分页
end

def set_pagy_thaalis_total
    @total = @tt.count
    @pagy, @thaalis = pagy_countless(@tt, items: 8)
end

关键说明

after_action的执行时机是动作执行完成、模板渲染结束之后,所以模板渲染时根本拿不到回调里赋值的变量。改用before_action或者动作内显式调用,就能解决这个时机问题。

内容的提问来源于stack exchange,提问作者Juzer Shakir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:55:16