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

如何基于VALID_EVENTS动态生成FactoryBot关联类事件工厂?

How to Reference External Variables for Event Types in Dynamic FactoryBot Factories?

Problem Context

You're trying to dynamically generate FactoryBot factories for your Event class, using the VALID_EVENTS hash from EventListConformanceValidator as the single source of truth. The goal is to create factories like foo_alert_event or bar_state_event that produce Event instances with valid type values matching the rules for each attribute (e.g., alert_events can only have onAlertLoad or onAlertUnload).

The issue with your current code is that the type block inside the factory definition can't access the correct klass (like foo/bar) and attribute (like alert_events) values from the outer loop—by the time FactoryBot executes these blocks, the loop variables have already been updated to their final iteration values.

Solution

The fix relies on Ruby's closure behavior to capture the correct values for each iteration. Instead of relying on the loop variables directly, we'll create local variables inside each loop iteration to hold the current klass, attribute, and its associated event types. This ensures each factory's type block references the values specific to that factory.

Here's the revised code:

FactoryBot.define do
  factory :event do
    type { nil }
  end

  EventListConformanceValidator::VALID_EVENTS.each do |klass, attribute_hash|
    # Iterate over each attribute and its valid event types directly
    attribute_hash.each do |attribute, event_types|
      # Capture current iteration values in local variables to preserve closure context
      current_klass = klass
      current_event_types = event_types

      # Generate the factory name as requested (e.g., foo_alert_event)
      factory_name = "#{current_klass}_#{attribute.to_s.singularize}".to_sym
      
      factory factory_name, class: Event, parent: :event do
        # Use the captured event types to pick a valid type
        type { current_event_types.keys.sample.to_s }
      end
    end
  end
end

Key Explanations:

  1. Direct Iteration Over Attribute Hash: Instead of extracting keys and uniq-ing them, we iterate directly over attribute_hash's key-value pairs. This lets us access the valid event types (event_types) for each attribute instantly, avoiding extra steps.
  2. Local Variable Capture: By assigning current_klass and current_event_types inside each iteration, we create a new variable binding that the factory's type block will capture. This prevents all factories from using the final loop values (a common pitfall with delayed-execution blocks in Ruby).
  3. Valid Type Selection: Using current_event_types.keys.sample.to_s picks a random valid event type from the allowed list for that attribute. If you need a fixed default instead of random, replace sample with first or specify a specific key.

Example Output:

  • Calling create(:foo_alert_event) will generate an Event with type set to either "onAlertLoad" or "onAlertUnload".
  • Calling create(:bar_user_event) will generate an Event with type set to "skipClicked".

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:16:36