ViewComponent预览中Rails URL生成失败,寻求解决方法
问题描述
我有一个使用插槽的ViewComponent组件,已实现预览渲染。测试环境可通过with_request_url指定请求URL,但预览环境无法使用。我想利用预览对购物车系统做隔离式浏览器测试,购物车属于主资源,其子组件需调用resource_cart_subresource_index_path路由,该路由要求传入:resource_id参数,因此触发了ActiveController::UrlGenerationError。尝试模板渲染仍未解决,求可行的解决思路。
代码示例:
# spec/components/cart_component_preview.rb class CartComponentPreview < ViewComponent::Preview def default user = FactoryBot.create(:user, :with_organizations, org_count: 1) @resource = FactoryBot.create(:resource, user:) FactoryBot.create(:cart, resource: @resource) render(Cart::MainComponent.new(resource: @resource)) do |component| component.with_subcomponent do Cart::SubComponent.new(resource: @resource).render_in(component) end component.with_info do Cart::InfoComponent.new(resource: @resource).render_in(component) end end end end
解决思路
手动注入请求路径参数
在预览方法里直接给request对象的路径参数赋值,让路由辅助方法能获取到:resource_id:def default user = FactoryBot.create(:user, :with_organizations, org_count: 1) @resource = FactoryBot.create(:resource, user:) FactoryBot.create(:cart, resource: @resource) # 新增这行:注入resource_id到请求参数 request.path_parameters[:resource_id] = @resource.id render(Cart::MainComponent.new(resource: @resource)) do |component| component.with_subcomponent do Cart::SubComponent.new(resource: @resource).render_in(component) end component.with_info do Cart::InfoComponent.new(resource: @resource).render_in(component) end end end子组件显式传递路由参数
修改子组件中调用路由辅助方法的逻辑,显式传入:resource_id,避免依赖上下文参数:# 以Cart::SubComponent为例 class Cart::SubComponent < ViewComponent::Base def initialize(resource:) @resource = resource end def subresource_index_path # 显式传入resource_id参数 resource_cart_subresource_index_path(resource_id: @resource.id) end end自定义预览控制器统一处理上下文
在初始化文件中配置自定义预览控制器,通过前置动作统一注入资源参数:- 编辑
config/initializers/view_component.rb:
ViewComponent::Preview.configure do |config| config.preview_controller = "PreviewController" end- 创建
app/controllers/preview_controller.rb:
class PreviewController < ActionController::Base before_action :inject_resource_id private def inject_resource_id # 如果预览中存在@resource实例变量,自动注入到路径参数 request.path_parameters[:resource_id] = @resource.id if defined?(@resource) && @resource.present? end end这样所有组件预览都能自动继承这个配置,无需重复编写参数注入代码。
- 编辑
手动构造URL替代路由辅助方法
直接使用url_for构造URL,完全脱离上下文参数依赖:# 在子组件中使用 def subresource_index_path url_for( controller: "cart_subresources", action: "index", resource_id: @resource.id, only_path: true # 生成相对路径,符合预览环境需求 ) end
内容的提问来源于stack exchange,提问作者crespire
相关产品推荐
相关产品推荐

