### Bundle and Verify Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Install gems and verify that the interactor generators are available. ```bash bundle install # Verify generators are available bundle exec rails generate --help | grep interactor ``` -------------------------------- ### Using the Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md An example of how to use an Organizer in a Rails controller to orchestrate multiple interactors. ```ruby class OrdersController < ApplicationController def create result = PlaceOrder.call( user: current_user, items: current_cart.items, shipping_address: params[:shipping_address], payment_method: params[:payment_method] ) if result.success? session.delete(:cart_id) redirect_to result.shipment, notice: "Order placed successfully" else render :new, alert: result.error end end end ``` -------------------------------- ### Calling a Nested Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Example of how to call a nested organizer from another part of the application. ```ruby result = Payment::ProcessCreditCard.call( card_number: params[:card_number], cvv: params[:cvv], amount: @order.total ) ``` -------------------------------- ### Class Names for Namespaced Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Example of how class names are structured for namespaced interactors, using `Invoice::CreateInvoice` as an example. ```ruby # app/interactors/invoice/create_invoice.rb class Invoice::CreateInvoice include Interactor # ... end # app/interactors/invoice/validate_items.rb class Invoice::ValidateItems include Interactor # ... end ``` -------------------------------- ### Usage Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example of how to use the Rake task to create an interactor. ```bash bundle exec rake interactors:create[place_order] ``` -------------------------------- ### Bundle Install Command Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/configuration.md Run bundle install after adding the gem to the Gemfile. ```bash bundle install ``` -------------------------------- ### Write Tests Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Example RSpec tests for the `AuthenticateUser` interactor, covering successful authentication and failure cases with invalid credentials. ```ruby require "rails_helper" RSpec.describe AuthenticateUser, type: :interactor do describe ".call" do let(:user) { create(:user, password: "secure_pass") } context "with valid credentials" do it "succeeds and returns the user" do result = AuthenticateUser.call( email: user.email, password: "secure_pass" ) expect(result).to be_a_success expect(result.user).to eq(user) end end context "with invalid email" do it "fails with error message" do result = AuthenticateUser.call( email: "invalid@example.com", password: "anything" ) expect(result).to be_a_failure expect(result.error).to eq("Invalid credentials") end end context "with invalid password" do it "fails with error message" do result = AuthenticateUser.call( email: user.email, password: "wrong_password" ) expect(result).to be_a_failure expect(result.error).to eq("Invalid credentials") end end end end ``` -------------------------------- ### File Structure Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/configuration.md Recommended file structure for organizing interactors and their specs. ```ruby app/ interactors/ authenticate_user.rb invoice/ calculate_tax.rb place_order.rb spec/ interactors/ authenticate_user_spec.rb invoice/ calculate_tax_spec.rb place_order_spec.rb ``` -------------------------------- ### Autoloading Integration Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example of how classes in app/interactors/ are automatically loaded in a Rails controller. ```ruby # No require needed - class is auto-available class OrdersController < ApplicationController def create result = PlaceOrder.call(...) # Auto-loads app/interactors/place_order.rb end end ``` -------------------------------- ### Execution Order Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Demonstrates the generation of an organizer and the resulting execution order of its steps. ```bash rails generate interactor:organizer checkout \ validate_payment \ authorize_charge \ create_order \ send_confirmation ``` -------------------------------- ### Shared Context Between Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Illustrates how to use `Interactor::Organizer` to chain interactors and share context between them, with examples of `ValidateCart`, `CalculateTotals`, `ApplyDiscounts`, and `CreateOrderRecord`. ```ruby class CreateOrder include Interactor::Organizer organize ValidateCart, CalculateTotals, ApplyDiscounts, CreateOrderRecord end # Each interactor reads and modifies context class ValidateCart include Interactor def call context.cart_valid = context.cart.items.any? end end class CalculateTotals include Interactor def call context.subtotal = context.cart.items.sum(&:price) end end class ApplyDiscounts include Interactor def call if context.user.premium? context.discount = context.subtotal * 0.1 context.subtotal -= context.discount end end end class CreateOrderRecord include Interactor def call # Access all previously set context values context.order = Order.create!( user: context.user, total: context.subtotal, discount: context.discount, items: context.cart.items ) end end ``` -------------------------------- ### Interactor Gem Usage Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example of how to include the Interactor module in a class and use the context. ```ruby # Provided by the interactor gem class PlaceOrder include Interactor # From interactor gem def call # context is an Interactor::Context instance context.success? # => true or false context.fail! # => mark as failure end end ``` -------------------------------- ### Basic Test Structure Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Demonstrates how to structure RSpec tests for an Interactor, including setup, success paths, and failure paths. ```ruby require "rails_helper" RSpec.describe PlaceOrder, type: :interactor do describe ".call" do # Setup let(:user) { create(:user) } let(:items) { create_list(:order_item, 2) } let(:shipping_address) { attributes_for(:address) } let(:payment_method) { attributes_for(:credit_card) } # Organize common context let(:context) do { user: user, items: items, shipping_address: shipping_address, payment_method: payment_method } end # Test success path context "with valid order" do it "succeeds and creates shipment" do result = described_class.call(context) expect(result).to be_a_success expect(result.shipment).to be_persisted expect(result.shipment.items.count).to eq(2) end it "charges the payment method" do expect(PaymentGateway).to receive(:charge) .with( amount: anything, card: payment_method, customer: user ) .and_return(double(success?: true, transaction_id: "TXN123")) described_class.call(context) end end # Test failure path context "with invalid items" do before do items.first.update(product: create(:product, in_stock: false)) end it "fails at validation step" do result = described_class.call(context) expect(result).to be_a_failure expect(result.error).to match(/out of stock/) end it "does not charge the payment method" do expect(PaymentGateway).not_to receive(:charge) described_class.call(context) end end # Test failure path context "when payment fails" do before do allow(PaymentGateway).to receive(:charge) .and_return(double(success?: false, message: "Insufficient funds")) end it "fails at payment step" do result = described_class.call(context) expect(result).to be_a_failure expect(result.error).to eq("Insufficient funds") end it "does not create shipment" do expect { described_class.call(context) }.not_to change(Shipment, :count) end end end end ``` -------------------------------- ### Use in a Controller Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Example of how to use the `AuthenticateUser` interactor within a Rails controller. It calls the interactor and handles success or failure. ```ruby class SessionsController < ApplicationController def create result = AuthenticateUser.call( email: params[:email], password: params[:password] ) if result.success? session[:user_id] = result.user.id redirect_to root_path else flash.now[:alert] = result.error render :new end end end ``` -------------------------------- ### Conditional Execution Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Demonstrates how an individual interactor can skip its execution based on conditions within the context, using `SendNotifications` as an example. ```ruby class SendNotifications include Interactor def call # Skip if user opted out return if context.user.notifications_disabled? send_email send_sms if context.user.phone_verified? end private def send_email NotificationMailer.deliver_later(context.user) end def send_sms SmsSender.send(context.user.phone, "Order #{context.order.id} confirmed") end end ``` -------------------------------- ### OrganizerGenerator Example Usage Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/method-reference.md Example usage for generating organizer classes. ```bash # Empty organizer rails generate interactor:organizer place_order # Creates: app/interactors/place_order.rb # spec/interactors/place_order_spec.rb # Generated class has commented organize example # Organizer with interactors rails generate interactor:organizer place_order charge_card send_email fulfill_order # Creates: app/interactors/place_order.rb with: # organize ChargeCard, SendEmail, FulfillOrder # spec/interactors/place_order_spec.rb # Namespaced organizer rails generate interactor:organizer checkout/place_order charge_card validate_payment # Creates: app/interactors/checkout/place_order.rb with class Checkout::PlaceOrder ``` -------------------------------- ### Namespace Support Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Demonstrates how nested directories in app/interactors/ map to class namespaces. ```ruby app/interactors/ ├── authenticate_user.rb → AuthenticateUser ├── invoice/ │ └── calculate_tax.rb → Invoice::CalculateTax └── payment/credit_card/ └── validate_cvv.rb → Payment::CreditCard::ValidateCvv ``` -------------------------------- ### Error Recovery with Retries Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Example of implementing retry logic within an Interactor to handle transient errors from a payment gateway. ```ruby class ProcessPaymentWithRetry include Interactor def call max_retries = 3 retries = 0 begin result = PaymentGateway.charge( amount: context.total, card: context.payment_method ) unless result.success? if retries < max_retries retries += 1 sleep(1) # Wait before retry retry else context.fail!(error: "Payment failed after #{max_retries} attempts") end end context.transaction_id = result.transaction_id rescue PaymentGateway::TimeoutError => e context.fail!(error: "Payment gateway timeout: #{e.message}") end end end ``` -------------------------------- ### Method Lookup Chain Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Demonstrates the method lookup chain for generator methods. ```ruby generator.generate # 1. Looks in InteractorGenerator → not found # 2. Looks in Interactor::Generator → FOUND # 3. Calls Interactor::Generator#generate ``` -------------------------------- ### Testing Interactor Failures with Debugging Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md An example of a test case that checks for Interactor success and logs context and error information upon failure. ```ruby it "processes the order" do result = PlaceOrder.call(context) if result.failure? puts "Context keys: #{result.context.keys}" puts "Error: #{result.error}" end expect(result).to be_a_success end ``` -------------------------------- ### organizer.erb Usage Pattern Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example showing how an organizer orchestrates multiple interactors and the equivalent manual calls. ```ruby # PlaceOrder organizer calls: ChargeCard, SendEmail, FulfillOrder result = PlaceOrder.call(order: order_data) # This is equivalent to: context = Interactor::Context.build(order: order_data) context = ChargeCard.call(context) context = SendEmail.call(context) if context.success? context = FulfillOrder.call(context) if context.success? ``` -------------------------------- ### Gem Specification Exports Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example from the gemspec file showing which files are exported. ```ruby spec.files = `git ls-files`.split($/) ``` -------------------------------- ### InteractorGenerator Example Usage Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/method-reference.md Example usage for generating interactor classes. ```bash # Basic interactor rails generate interactor place_order # Creates: app/interactors/place_order.rb # spec/interactors/place_order_spec.rb # Namespaced interactor rails generate interactor invoice/calculate_tax # Creates: app/interactors/invoice/calculate_tax.rb # spec/interactors/invoice/calculate_tax_spec.rb ``` -------------------------------- ### Force Overwrite Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Demonstrates how to use the `--force` option to overwrite existing files without confirmation. ```bash # Overwrite existing files without confirmation rails generate interactor place_order --force ``` -------------------------------- ### Batch Operations Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md This example illustrates generating multiple related interactors in a batch using a loop, followed by creating an organizer for them. ```bash # Generate multiple related interactors for name in validate_user create_account send_welcome_email; do rails generate interactor signup/$name done # Generates: # app/interactors/signup/validate_user.rb # app/interactors/signup/create_account.rb # app/interactors/signup/send_welcome_email.rb # Then create an organizer rails generate interactor:organizer signup/complete_signup \ validate_user \ create_account \ send_welcome_email ``` -------------------------------- ### Gemfile Installation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/configuration.md Add the interactor-rails gem to your application's Gemfile. ```ruby gem "interactor-rails", "~> 2.3" ``` -------------------------------- ### spec.erb Example Shared Configuration Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of configuring shared behavior for interactor specs. ```ruby # spec/spec_helper.rb or spec/rails_helper.rb RSpec.configure do |config| config.define_derived_metadata(file_path: /spec\/interactors/) do |metadata| metadata[:type] = :interactor end config.include InteractorHelpers, type: :interactor end ``` -------------------------------- ### Generate Multiple Interactors at Once Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md This example shows how to generate several individual interactors and then combine them into an organizer interactor using a bash script. ```bash #!/bin/bash rails generate interactor order/validate_items rails generate interactor order/calculate_totals rails generate interactor order/process_payment rails generate interactor order/send_confirmation rails generate interactor:organizer order/place_order \ validate_items \ calculate_totals \ process_payment \ send_confirmation ``` -------------------------------- ### Generated Nested Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md The content of the generated nested organizer file. ```ruby class Payment::ProcessCreditCard include Interactor::Organizer organize ValidateCvv, AuthorizeCharge end ``` -------------------------------- ### InteractorGenerator - Usage Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/generators.md Command-line examples for generating interactor classes. ```bash # Basic interactor rails generate interactor authenticate_user # Namespaced interactor rails generate interactor invoice/calculate_tax # Generates both class file and test file automatically ``` -------------------------------- ### Inspecting Organizer Flow with Logging Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Shows how to add around callbacks to an Interactor Organizer to log the execution order of individual interactors. ```ruby # Add logging to see execution order class PlaceOrder include Interactor::Organizer organize ValidateCart, CalculateTotals, CreateOrder, SendConfirmation around do |interactor| Rails.logger.info("Starting: #{interactor.class}") interactor.call Rails.logger.info("Finished: #{interactor.class}") end end ``` -------------------------------- ### Generating a Nested Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Command to generate a nested organizer that includes other interactors. ```bash rails generate interactor:organizer payment/process_credit_card \ validate_cvv \ authorize_charge ``` -------------------------------- ### Generated Organizer Class Structure (With Interactors) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md An example of a generated organizer class with specific interactors listed in the `organize` macro. ```ruby class PlaceOrder include Interactor::Organizer organize ValidateItems, CalculateTotals, ProcessPayment end ``` -------------------------------- ### Organizer Implementation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md The generated `PlaceOrder` organizer class, which includes `Interactor::Organizer` and lists the sequence of interactors to be executed. ```ruby class PlaceOrder include Interactor::Organizer organize ValidateItems, CalculateTotals, ProcessPayment, CreateShipment, SendConfirmationEmail end ``` -------------------------------- ### organizer.erb Rendered Output Example 2 Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of rendered output for 'rails generate interactor:organizer place_order charge_card send_email fulfill_order'. ```ruby class PlaceOrder include Interactor::Organizer organize ChargeCard, SendEmail, FulfillOrder end ``` -------------------------------- ### organizer.erb Rendered Output Example 3 Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of rendered output for 'rails generate interactor:organizer invoice/process_payment validate_card charge_card send_receipt'. ```ruby class Invoice::ProcessPayment include Interactor::Organizer organize ValidateCard, ChargeCard, SendReceipt end ``` -------------------------------- ### Configure Test Framework (RSpec) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Example configuration in `config/generators.rb` to set RSpec as the default test framework. ```ruby # config/generators.rb Rails.application.configure do config.generators do |g| g.test_framework :rspec # or g.test_framework :test_unit end end ``` -------------------------------- ### Interactor Rails Gemspec Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/version-compatibility.md An example of the interactor-rails.gemspec file, showing dependencies and metadata for version 2.3.0. ```ruby Gem::Specification.new do |spec| spec.name = "interactor-rails" spec.version = "2.3.0" spec.author = "Collective Idea" spec.email = "info@collectiveidea.com" spec.description = "Interactor Rails provides Rails support for the Interactor gem." spec.summary = "Rails support for Interactor" spec.homepage = "https://github.com/collectiveidea/interactor-rails" spec.license = "MIT" spec.add_dependency "interactor", "~> 3.0" spec.add_dependency "railties", ">= 7.0" end ``` -------------------------------- ### interactor.erb Rendered Output Example 2 Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of rendered output for 'rails generate interactor invoice/place_order'. ```ruby class Invoice::PlaceOrder include Interactor def call # TODO end end ``` -------------------------------- ### Generating Namespaced Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Command to generate interactors within nested namespaces. ```bash rails generate interactor payment/credit_card/validate_cvv rails generate interactor payment/credit_card/authorize_charge rails generate interactor payment/bank_transfer/verify_account ``` -------------------------------- ### rails generate interactor Usage Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example usage of the `rails generate interactor` command. ```bash rails generate interactor place_order rails generate interactor invoice/calculate_tax ``` -------------------------------- ### Vim Generator Command Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Example of using the `vim-rails` plugin to generate an interactor. ```vim :Rails generate interactor place_order ``` -------------------------------- ### Accessing Generators Programmatically in Tests or Scripts Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example of how to instantiate and call an Interactor generator programmatically. ```ruby require "generators/interactor" require "generators/interactor_generator" require "generators/interactor/organizer_generator" # Instantiate generator generator = InteractorGenerator.new( ["place_order"], {}, { destination_root: Rails.root } ) # Call generate method generator.generate ``` -------------------------------- ### Checking Context Values on Failure Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Demonstrates how to log the context values when an Interactor fails, aiding in debugging. ```ruby result = PlaceOrder.call( user: current_user, items: cart.items ) if result.failure? Rails.logger.error("Order failed: #{result.error}") Rails.logger.debug("Context at failure: #{result.context.inspect}") end ``` -------------------------------- ### rails generate interactor:organizer Usage Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example usage of the `rails generate interactor:organizer` command. ```bash rails generate interactor:organizer place_order charge_card send_email rails generate interactor:organizer checkout/process ``` -------------------------------- ### Usage Example: Namespaced Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/generators.md Command to generate a namespaced organizer. ```bash rails generate interactor:organizer checkout/place_order charge_card send_email ``` -------------------------------- ### Test Data: Set up common context in let blocks Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example of setting up common context with user, items, and amount in a let block. ```ruby let(:valid_context) do { user: create(:user), items: create_list(:item, 2), amount: 100 } end ``` -------------------------------- ### Usage Example: Empty Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/generators.md Command to generate an empty organizer. ```bash rails generate interactor:organizer place_order ``` -------------------------------- ### Basic Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md A simple Interactor that creates a shipment record. ```ruby class CreateShipment include Interactor def call context.shipment = Shipment.create!( order_items: context.items, shipping_address: context.shipping_address, tracking_number: generate_tracking_number ) end end ``` ```ruby class SendConfirmationEmail include Interactor def call OrderConfirmationMailer.deliver_later( user: context.user, order: context.order, shipment: context.shipment ) end end ``` -------------------------------- ### Organizer with interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/method-reference.md Example of an organizer class with explicitly listed interactors. ```ruby class PlaceOrder include Interactor::Organizer organize ChargeCard, SendEmail end ``` -------------------------------- ### Generate an Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Generate an organizer interactor using the `interactor:organizer` generator, specifying the sequence of interactors to be organized. ```bash rails generate interactor:organizer place_order \ validate_items \ calculate_totals \ process_payment \ create_shipment \ send_confirmation_email ``` -------------------------------- ### File Organization Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/overview.md Illustrates the recommended directory structure for organizing interactors, including namespaced ones. ```plaintext app/interactors/ place_order.rb # PlaceOrder class send_email.rb # SendEmail class invoice/ calculate_tax.rb # Invoice::CalculateTax class place_order.rb # Invoice::PlaceOrder class payment/ charge_card.rb # Payment::ChargeCard class validate_cvv.rb # Payment::ValidateCvv class ``` -------------------------------- ### Generated Namespaced Interactor Files Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md The file structure created by the nested namespace generation command. ```text Creates: app/interactors/payment/ ├── credit_card/ │ ├── validate_cvv.rb # Payment::CreditCard::ValidateCvv │ └── authorize_charge.rb # Payment::CreditCard::AuthorizeCharge └── bank_transfer/ └── verify_account.rb # Payment::BankTransfer::VerifyAccount ``` -------------------------------- ### Test Data: Use before/setup for shared state Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example of using a before block to set up shared state, like mocking a payment gateway charge. ```ruby before do allow(PaymentGateway).to receive(:charge).and_return(...) end ``` -------------------------------- ### Using Namespaced Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Demonstrates how to call namespaced interactors directly within a Rails application without needing explicit `require` statements. ```ruby # Automatically available in Rails app (no require needed) result = Invoice::CreateInvoice.call(items: order.items) ``` -------------------------------- ### Usage Example: Organizer with Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/generators.md Command to generate an organizer with specified interactors. ```bash rails generate interactor:organizer place_order charge_card send_confirmation fulfill_order ``` -------------------------------- ### Testing Individual Interactors in Isolation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Shows how to test a single Interactor, like `ValidateItems`, by providing only the necessary context. ```ruby require "rails_helper" RSpec.describe ValidateItems, type: :interactor do let(:items) { create_list(:order_item, 2) } context "with valid items" do it "succeeds" do result = described_class.call(items: items) expect(result).to be_a_success end end context "with empty items" do it "fails with appropriate error" do result = described_class.call(items: []) expect(result).to be_a_failure expect(result.error).to eq("Order must contain items") end end context "with out-of-stock items" do before do items.first.product.update(in_stock: false) end it "fails with product name in error" do result = described_class.call(items: items) expect(result).to be_a_failure expect(result.error).to include(items.first.product.name) end end end ``` -------------------------------- ### Implement CalculateTotals Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Implementation of the `CalculateTotals` interactor, which calculates the subtotal, tax, and total amount for the order. ```ruby # app/interactors/calculate_totals.rb class CalculateTotals include Interactor def call context.subtotal = context.items.sum(&:price) context.tax = context.subtotal * 0.08 context.total = context.subtotal + context.tax end end ``` -------------------------------- ### Mocking and Stubbing Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md RSpec example demonstrating how to mock and stub external services within an interactor test. ```ruby describe ProcessPayment do describe ".call" do let(:payment_service) { instance_double(PaymentGateway) } before do allow(PaymentGateway).to receive(:new).and_return(payment_service) allow(payment_service).to receive(:charge) .with(amount: 100, card: anything) .and_return(double(success?: true, transaction_id: "TX123")) end it "charges the card" do result = ProcessPayment.call( amount: 100, card: card_data ) expect(payment_service).to have_received(:charge) .with(amount: 100, card: card_data) expect(result.transaction_id).to eq("TX123") end end end ``` -------------------------------- ### spec.erb Rendered Output Example (Older Apps) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Rendered output for an older app with only spec_helper.rb. ```ruby require "spec_helper" RSpec.describe Invoice::PlaceOrder, type: :interactor do describe ".call" do pending "add some examples to (or delete) #{__FILE__}" end end ``` -------------------------------- ### Interactor::Generator Public Methods Detail Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Example calls to public methods of `Interactor::Generator`. ```ruby # Class method Interactor::Generator.source_root # => "/path/to/gem/lib/generators/templates" # Instance methods (called by Rails during generation) generator = InteractorGenerator.new(['place_order']) generator.source_root # => template directory generator.generate # => creates files generator.use_test_unit? # => true or false generator.rspec_helper_file # => "rails_helper" or "spec_helper" ``` -------------------------------- ### Generate Namespaced Interactors Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Generate interactors within a namespace (e.g., 'invoice') to organize them by feature or domain. ```bash rails generate interactor invoice/create_invoice rails generate interactor invoice/validate_items rails generate interactor invoice/calculate_totals rails generate interactor invoice/save_to_database ``` -------------------------------- ### Example Interactor and Organizer Structure Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/overview.md Demonstrates the basic structure of a simple interactor and an organizer that chains interactors. ```ruby class AuthenticateUser include Interactor def call if user = User.find_by(email: context.email) context.user = user else context.fail!(error: "User not found") end end end class Login include Interactor::Organizer organize AuthenticateUser, CreateSession end ``` -------------------------------- ### Run Bundle Update Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/version-compatibility.md Command to run after updating the Gemfile to install the new gem version. ```bash bundle update interactor-rails ``` -------------------------------- ### Test Data: Use factories instead of fixtures Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example of using factories to create test data for users and order items. ```ruby let(:user) { create(:user) } let(:items) { create_list(:order_item, 3) } ``` -------------------------------- ### Implement ProcessPayment Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Implementation of the `ProcessPayment` interactor, which handles charging the customer using a payment gateway and records the transaction ID. ```ruby # app/interactors/process_payment.rb class ProcessPayment include Interactor def call result = PaymentGateway.charge( amount: context.total, card: context.payment_method, customer: context.user ) unless result.success? context.fail!(error: "Payment failed: #{result.message}") end context.transaction_id = result.transaction_id end end ``` -------------------------------- ### Running Specific Test Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Commands to run specific interactor tests, either a single spec file or a single example within a file. ```bash # RSpec - single spec bundle exec rspec spec/interactors/place_order_spec.rb # RSpec - single example bundle exec rspec spec/interactors/place_order_spec.rb:10 # TestUnit - single test bundle exec rails test test/interactors/place_order_test.rb ``` -------------------------------- ### Autoloading Example in a Rails Controller Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/overview.md Shows how interactors are automatically available in Rails controllers without explicit require statements. ```ruby class UsersController < ApplicationController def create # PlaceOrder is automatically available, no require needed result = PlaceOrder.call(order_params) if result.success? redirect_to result.order else render :new, alert: result.error end end end ``` -------------------------------- ### Import Paths for Tests Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Shows how to require necessary files for testing interactors. ```ruby # In tests require "spec_helper" # or "rails_helper" require "interactor/rails" # Test the gem itself require "rspec" require "interactor/rails" require "generators/interactor" ``` -------------------------------- ### Test Organization: One test file per interactor/organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example showing the convention of having a corresponding test file for each interactor file. ```ruby app/interactors/place_order.rb spec/interactors/place_order_spec.rb ``` -------------------------------- ### Implement the Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Implement the `call` method for the `AuthenticateUser` interactor. It finds a user by email and password, and either sets the user in the context or fails with an error message. ```ruby class AuthenticateUser include Interactor def call user = User.find_by(email: context.email) if user&.authenticate(context.password) context.user = user else context.fail!(error: "Invalid credentials") end end end ``` -------------------------------- ### Gemfile update required Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/version-compatibility.md Example showing the required Gemfile update for upgrading from version 2.2.1 to 2.3.0. ```ruby # Gemfile update required # Old: gem "interactor-rails", "~> 2.2" # New: gem "interactor-rails", "~> 2.3" ``` -------------------------------- ### Generate an organizer class Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Generates an organizer class that chains multiple interactors. ```bash # Empty organizer rails generate interactor:organizer place_order # Creates: app/interactors/place_order.rb with empty organize list # Organizer with interactors rails generate interactor:organizer place_order \ validate_items \ calculate_totals \ process_payment # Creates: app/interactors/place_order.rb # organize ValidateItems, CalculateTotals, ProcessPayment # Namespaced organizer rails generate interactor:organizer checkout/process_payment \ validate_card \ charge_card \ send_receipt ``` -------------------------------- ### interactor.erb Usage Pattern Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of how a generated interactor is expanded with business logic. ```ruby class PlaceOrder include Interactor def call # Validate input context.fail!(error: "Invalid order") unless context.order.valid? # Perform business logic context.invoice = Invoice.create(order: context.order) # Success is implicit if context.fail! is not called end end ``` -------------------------------- ### Generate an Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Generates an organizer interactor with multiple steps, converting underscored names to CamelCase. ```bash rails generate interactor:organizer order_fulfillment \ validate_payment \ charge_card \ send_confirmation \ create_shipment ``` -------------------------------- ### Shared Examples for Interactor Behavior Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Uses RSpec's shared examples to define and reuse common interactor test cases. ```ruby shared_examples "an interactor" do it "is a callable interactor" do expect(described_class.new).to respond_to(:call) end it "has a context object" do result = described_class.call expect(result).to be_a Interactor::Context end end describe PlaceOrder do it_behaves_like "an interactor" end ``` -------------------------------- ### organizer.erb Name Classification Example Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of how interactor names are classified from underscored to proper class names. ```text charge_card → ChargeCard send_email → SendEmail fulfill_order → FulfillOrder validate_payment → ValidatePayment ``` -------------------------------- ### Gem Loading Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Shows how the gem is loaded in a Rails application. ```ruby gem "interactor-rails" # Rails automatically requires lib/interactor/rails.rb ``` -------------------------------- ### Abbreviated Organizer Generation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Shorthand for generating an organizer interactor. ```bash rails g interactor:organizer process_payment validate_card charge_card ``` -------------------------------- ### Generate with Custom Output Directory Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Demonstrates how Rails generators typically place files in `app/interactors/` and provides a manual workaround to place them in a different directory like `app/services/`. ```bash # Still generates to app/interactors/ (this is the Rails convention) rails generate interactor place_order # To use a different location, manually move files: mv app/interactors/place_order.rb app/services/place_order.rb # Then update the require statement or autoload path ``` -------------------------------- ### Import Paths for Applications (External) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Illustrates how to require and use interactors within a Rails application. ```ruby # In Rails app require "interactor/rails" # Or just 'interactor-rails' in Gemfile # Classes auto-available in app/interactors/ PlaceOrder # Auto-loaded Invoice::PlaceOrder # Auto-loaded ``` -------------------------------- ### Gemfile Installation Source: https://github.com/collectiveidea/interactor-rails/blob/main/README.md Add the interactor-rails gem to your application's Gemfile. ```ruby gem "interactor-rails", "~> 2.0" ``` -------------------------------- ### Import Paths for Generators (Internal) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Shows how generator files require the base generator class. ```ruby # lib/generators/interactor_generator.rb require "generators/interactor" # lib/generators/interactor/organizer_generator.rb require "generators/interactor" ``` -------------------------------- ### Test an Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/README.md Example RSpec test for an interactor. ```ruby require "rails_helper" RSpec.describe PlaceOrder, type: :interactor do describe ".call" do it "succeeds with valid input" do result = PlaceOrder.call(items: [...]) expect(result).to be_a_success end end end ``` -------------------------------- ### Testing Context Modifications Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md RSpec example for testing how an interactor modifies its context. ```ruby describe ".call" do it "adds values to context" do result = CalculateTotals.call( items: [ double(price: 10.0), double(price: 20.0) ] ) expect(result.subtotal).to eq(30.0) expect(result.tax).to eq(2.4) # 30 * 0.08 expect(result.total).to eq(32.4) end end ``` -------------------------------- ### Interactor Implementation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/README.md Example implementation of a basic interactor class. ```ruby class AuthenticateUser include Interactor def call # Business logic here end end ``` -------------------------------- ### Generated Test File for Organizer Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md The default RSpec test file generated for an organizer interactor. ```ruby require "rails_helper" RSpec.describe PlaceOrder, type: :interactor do describe ".call" do pending "add some examples to (or delete) #{__FILE__}" end end ``` -------------------------------- ### Rakefile or lib/tasks/custom.rake Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Defines a Rake task to generate a new interactor. ```ruby namespace :interactors do desc "Generate a new interactor" task :create, [:name] => :environment do |task, args| `bundle exec rails generate interactor #{args[:name]}` end end ``` -------------------------------- ### Assertions: Verify context modifications Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example assertion to verify modifications to context, such as the total amount. ```ruby expect(result.total).to eq(expected_total) ``` -------------------------------- ### Implement ValidateItems Interactor Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/usage-guide.md Implementation of the `ValidateItems` interactor, which checks if the order items are present and in stock. ```ruby # app/interactors/validate_items.rb class ValidateItems include Interactor def call if context.items.empty? context.fail!(error: "Order must contain items") end context.items.each do |item| unless item.product.in_stock? context.fail!(error: "Product #{item.product.name} is out of stock") end end end end ``` -------------------------------- ### Skip Test File Generation (Global) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Global configuration in `config/generators.rb` to skip test file generation for all generators. ```ruby # Globally in config/generators.rb Rails.application.configure do config.generators do |g| g.skip_test_files true end end ``` -------------------------------- ### Assertions: Check error messages are clear Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example assertion to check if error messages are clear and informative. ```ruby expect(result.error).to eq("Order must contain items") ``` -------------------------------- ### TestUnit: Testing Failure Path Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md Example of a TestUnit test case verifying the failure conditions of an interactor. ```ruby class AuthenticateUserTest < ActiveSupport::TestCase test "fails with invalid email" do result = AuthenticateUser.call( email: "invalid@example.com", password: "password" ) assert result.failure? assert_equal result.error, "Invalid credentials" end end ``` -------------------------------- ### Interactor::OrganizerGenerator Implementation Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/architecture.md Demonstrates the implementation of Interactor::OrganizerGenerator, extending Interactor::Generator with an argument for multiple interactors. ```ruby module Interactor class OrganizerGenerator < Interactor::Generator argument :interactors, type: :array, default: [], banner: "name name" end end ``` -------------------------------- ### Testing Organizers Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/testing.md RSpec examples for testing interactors that act as organizers, including success and failure scenarios. ```ruby describe PlaceOrder do let(:user) { create(:user) } let(:items) { create_list(:item, 2) } context "with valid order" do it "completes all steps" do result = PlaceOrder.call( user: user, items: items ) expect(result).to be_a_success expect(result.shipment).to be_persisted expect(result.confirmation_sent).to be(true) end end context "when payment fails" do before do allow(PaymentGateway).to receive(:charge) .and_return(double(success?: false)) end it "stops execution at payment step" do result = PlaceOrder.call( user: user, items: items ) expect(result).to be_a_failure # Shipment creation is skipped expect(Shipment.count).to eq(0) end end end ``` -------------------------------- ### Generate a basic interactor class Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Generates a basic interactor class with a `call` method. ```bash rails generate interactor authenticate_user # Creates: app/interactors/authenticate_user.rb # spec/interactors/authenticate_user_spec.rb # Namespaced interactor rails generate interactor invoice/place_order # Creates: app/interactors/invoice/place_order.rb # spec/interactors/invoice/place_order_spec.rb # Deep namespace rails generate interactor payment/credit_card/validate_cvv # Creates: app/interactors/payment/credit_card/validate_cvv.rb # spec/interactors/payment/credit_card/validate_cvv_spec.rb # Abbreviation rails g interactor send_email # Creates: app/interactors/send_email.rb # spec/interactors/send_email_spec.rb # With skip option rails generate interactor process_order --skip-test-files # Creates: app/interactors/process_order.rb (no test file) ``` -------------------------------- ### Output variable with assignment Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/templates.md Example of outputting a variable with assignment in an ERB template. ```erb class <%= class_name %> ``` -------------------------------- ### Gem Specification Main Entry Point Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/entry-points.md Indicates the main entry point file for the gem. ```ruby # lib/interactor/rails.rb ``` -------------------------------- ### Skip Test File Generation (Single) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/cli-reference.md Command-line option to skip generating test files for a single interactor generation. ```bash # For a single generation rails generate interactor place_order --skip-test-files ``` -------------------------------- ### Generated Organizer File (Basic) Source: https://github.com/collectiveidea/interactor-rails/blob/main/_autodocs/api-reference/generators.md Example of a generated organizer file with no interactors specified. ```ruby class PlaceOrder include Interactor::Organizer # organize Interactor1, Interactor2 end ```