Module: Service::Base

Defined Under Namespace

Classes: Context, Failure

Class Method Summary collapse

Class Method Details

.model(name = :model, step_name = :"fetch_#{name}", optional: false) ⇒ Object

Evaluates arbitrary code to build or fetch a model (typically from the DB). If the step returns a falsy value, then the step will fail.

It stores the resulting model in context[:model] by default (can be customized by providing the name argument).

Examples:

model :channel

private

def fetch_channel(channel_id:)
  Chat::Channel.find_by(id: channel_id)
end

Parameters:

  • name (Symbol) (defaults to: :model)

    name of the model

  • step_name (Symbol) (defaults to: :"fetch_#{name}")

    name of the method to call for this step

  • optional (Boolean) (defaults to: false)

    if true, then the step won’t fail if its return value is falsy.



# File 'lib/service/base.rb', line 315

.options(&block) ⇒ Object

This is used to define options allowing to parameterize the service behavior. The resulting options are available in ‘context`.

Examples:

options do
  attribute :my_option, :boolean, default: false
end

Parameters:

  • block (Proc)

    a block containing options definition



# File 'lib/service/base.rb', line 425

.params(name = :default, default_values_from: nil, &block) ⇒ Object

Checks the validity of the input parameters. Implements ActiveModel::Validations and ActiveModel::Attributes.

It stores the resulting contract in context[:params] by default (can be customized by providing the name argument).

Examples:

params do
  attribute :name
  validates :name, presence: true
end

Parameters:

  • name (Symbol) (defaults to: :default)

    name for this contract

  • default_values_from (Symbol) (defaults to: nil)

    name of the model to get default values from

  • block (Proc)

    a block containing validations



# File 'lib/service/base.rb', line 373

.policy(name = :default, class_name: nil) ⇒ Object

Performs checks related to the state of the system. If the step doesn’t return a truthy value, then the policy will fail.

When using a policy object, there is no need to define a method on the service for the policy step. The policy object ‘#call` method will be called and if the result isn’t truthy, a `#reason` method is expected to be implemented to explain the failure.

Policy objects are usually useful for more complex logic.

Examples:

Without a policy object

policy :no_direct_message_channel

private

def no_direct_message_channel(channel:)
  !channel.direct_message_channel?
end

With a policy object

# in the service object
policy :no_direct_message_channel, class_name: NoDirectMessageChannelPolicy

# in the policy object File
class NoDirectMessageChannelPolicy < PolicyBase
  def call
    !context.channel.direct_message_channel?
  end

  def reason
    "Direct message channels aren’t supported"
  end
end

Parameters:

  • name (Symbol) (defaults to: :default)

    name for this policy

  • class_name (Class) (defaults to: nil)

    a policy object (should inherit from PolicyBase)



# File 'lib/service/base.rb', line 335

.step(name) ⇒ Object

Runs arbitrary code. To mark a step as failed, a call to #fail! needs to be made explicitly.

Examples:

step :update_channel

private

def update_channel(channel:, params_to_edit:)
  channel.update!(params_to_edit)
end

using #fail! in a step

step :save_channel

private

def save_channel(channel:)
  fail!("something went wrong") if !channel.save
end

Parameters:

  • name (Symbol)

    the name of this step



# File 'lib/service/base.rb', line 390

.transaction(&block) ⇒ Object

Runs steps inside a DB transaction.

Examples:

transaction do
  step :prevents_slug_collision
  step :soft_delete_channel
  step :log_channel_deletion
end

Parameters:

  • block (Proc)

    a block containing steps to be run inside a transaction



# File 'lib/service/base.rb', line 413