Loading...
Loading...
Compare original and translation side by side
| Service Objects | ActiveInteraction |
|---|---|
| No standard interface | Consistent |
| Manual type checking | Built-in type declarations |
| Manual validation | Standard Rails validations |
| Hard to compose | Native composition |
| Verbose boilerplate | Clean, self-documenting |
| 服务对象 | ActiveInteraction |
|---|---|
| 无标准接口 | 统一的 |
| 手动类型检查 | 内置类型声明 |
| 手动验证 | 标准Rails验证 |
| 难以组合 | 原生支持组合 |
| 冗余样板代码 | 简洁、自文档化 |
undefinedundefinedundefinedundefinedundefinedundefined# Validations
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :name, presence: true
# Main logic
def execute
user = User.create!(
email: email,
name: name,
password: password || SecureRandom.alphanumeric(32)
)
UserMailer.welcome(user).deliver_later
user # Return value becomes outcome.result
endundefined# Validations
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :name, presence: true
# Main logic
def execute
user = User.create!(
email: email,
name: name,
password: password || SecureRandom.alphanumeric(32)
)
UserMailer.welcome(user).deliver_later
user # Return value becomes outcome.result
endundefinedundefinedundefinedundefinedundefinedclass MyInteraction < ActiveInteraction::Base
# Primitives
string :name
integer :age
float :price
boolean :active
symbol :status
# Date/Time
date :birthday
time :created_at
date_time :scheduled_at
# Complex types
array :tags
hash :metadata
# Model instances
object :user, class: User
# Typed arrays
array :emails, default: [] do
string
end
# Optional with default
string :optional_field, default: nil
integer :count, default: 0
endclass MyInteraction < ActiveInteraction::Base
# Primitives
string :name
integer :age
float :price
boolean :active
symbol :status
# Date/Time
date :birthday
time :created_at
date_time :scheduled_at
# Complex types
array :tags
hash :metadata
# Model instances
object :user, class: User
# Typed arrays
array :emails, default: [] do
string
end
# Optional with default
string :optional_field, default: nil
integer :count, default: 0
endmodule Users
class Register < ActiveInteraction::Base
string :email, :name, :password
def execute
# Compose calls another interaction
user = compose(Users::Create,
email: email,
name: name,
password: password
)
# Errors automatically merged if nested fails
compose(Users::SendWelcomeEmail, user: user)
user
end
end
endmodule Users
class Register < ActiveInteraction::Base
string :email, :name, :password
def execute
# Compose calls another interaction
user = compose(Users::Create,
email: email,
name: name,
password: password
)
# Errors automatically merged if nested fails
compose(Users::SendWelcomeEmail, user: user)
user
end
end
endclass ArticlesController < ApplicationController
def create
outcome = Articles::Create.run(
title: params[:article][:title],
body: params[:article][:body],
author: current_user
)
if outcome.valid?
redirect_to article_path(outcome.result), notice: "Article created"
else
@article = Article.new(article_params)
@article.errors.merge!(outcome.errors)
render :new, status: :unprocessable_entity
end
end
endclass ArticlesController < ApplicationController
def create
outcome = Articles::Create.run(
title: params[:article][:title],
body: params[:article][:body],
author: current_user
)
if outcome.valid?
redirect_to article_path(outcome.result), notice: "Article created"
else
@article = Article.new(article_params)
@article.errors.merge!(outcome.errors)
render :new, status: :unprocessable_entity
end
end
endRSpec.describe Users::Create do
let(:valid_params) { { email: "user@example.com", name: "John" } }
it "creates user with valid inputs" do
expect { described_class.run(valid_params) }
.to change(User, :count).by(1)
end
it "returns valid outcome" do
outcome = described_class.run(valid_params)
expect(outcome).to be_valid
expect(outcome.result).to be_a(User)
end
it "validates email format" do
outcome = described_class.run(valid_params.merge(email: "invalid"))
expect(outcome).not_to be_valid
expect(outcome.errors[:email]).to be_present
end
endRSpec.describe Users::Create do
let(:valid_params) { { email: "user@example.com", name: "John" } }
it "creates user with valid inputs" do
expect { described_class.run(valid_params) }
.to change(User, :count).by(1)
end
it "returns valid outcome" do
outcome = described_class.run(valid_params)
expect(outcome).to be_valid
expect(outcome.result).to be_a(User)
end
it "validates email format" do
outcome = described_class.run(valid_params.merge(email: "invalid"))
expect(outcome).not_to be_valid
expect(outcome.errors[:email]).to be_present
end
endreferences/active-interaction.mdreferences/active-interaction.md