Рубрики
Без рубрики

Как использовать сценарий транзакции (AKA сервисных объектов) в Ruby на рельсах. Простой пример

Логика небольших приложений может присутствовать как серия транзакций. Используя транзакцию SCR … с меткой Ruby, Rails, Python, JavaScript.

Логика небольших приложений может присутствовать как серия транзакций. Используя шаблон сценариев транзакции, мы получаем приложение, которое легче поддерживать, чтобы покрыть тестами и масштабированием.

Настройка проблемы

Есть ruby на приложении API Rails, который имеет пост, пользователь и как модели. Пользователи должны быть в состоянии понравиться сообщения.

Давайте добавим контроллер, который обрабатывает кнопки, нажмите на кнопки.

module Api
  class LikesController < ApplicationController
    def update
      @user = User.find(params['user_id'])
      @post = Post.find(params['post_id'])

      like = @post.likes.find_or_initialize_by(user: @user)

      if like.persisted?
        like.destroy!
        render json: { isLiked: false }
      else
        like.save!
        render json: { isLiked: true }
      end
    end
  end
end

Очевидные недостатки этого кода являются:

  • Контроллер реализует бизнес-логику, хотя контроллеры должны быть только координировать взаимодействие между пользователем, представлениями и моделью.
  • Чтобы покрыть этот код тестами, вам необходимо проверить все действие контроллера. Чтобы проверить контроллер, вам обычно нужно делать больше предварительных условий.
  • Если у вас есть два контроллера для любит, вам нужно повторить код.

Первые тесты

Давайте напишем тест и, таким образом, решить две проблемы:

  • Определите интерфейс обслуживания.
  • Получите готовый тест.
require 'test_helper'

class ToggleLikeActionScriptTest < ActiveSupport::TestCase
  def setup
    @user = users(:john_doe)
    @post = posts(:lorem_ipsum)
  end

  def test_it_creates_like
    result = ToggleLikeActionScript.new(@user, @post).perform

    assert result.value
    assert @user.likes.where(post: @post).present?
  end

  def test_it_destroys_like
    @user.likes.create(post: @post)

    result = ToggleLikeActionScript.new(@user, @post).perform

    assert_not result.value
    assert @user.likes.where(post: @post).blank?
  end

  def test_it_show_errros_on_fail_case
    result = ToggleLikeActionScript.new(@user, nil).perform

    assert_nil result.value
    assert_not_empty result.errors
  end
end

Теперь у вас есть тест, и вы можете внедрить услугу.

Реализация услуг

Из тестов вы можете увидеть, что сервис наиболее тесно следует за Шаблон сценария транзакции или вид сервисного объекта.

Сценарий транзакции должен соответствовать единственному принципу ответственности.

class ToggleLikeActionScript
  Result = Struct.new(:success?, :errors, :value)

  def initialize(user, post)
    @user = user
    @post = post
  end

  def perform
    like = @post.likes.find_or_initialize_by(user: @user)

    if like.persisted?
      like.destroy!
      Result.new(true, [], false)
    else
      like.save!
      Result.new(true, [], true)
    end
  rescue StandardError => e
    Result.new(false, [e], nil)
  end
end

Итак, у нас есть услуга и тест. Давайте очистим контроллер:

module Api
  class LikesController < ApplicationController
    def update
      @user = User.find(params["user_id"])
      @post = Post.find(params["post_id"])

      result = ToggleLikeActionScript.new(@user, @post).perform

      if result.success?
        render json: { isLiked: result.value }
      else
        render json: { errors: result.errors }
      end
    end
  end
end

Как видите, наш контроллер теперь выглядел чище. « Toggle, как «функциональность» теперь берет только одну строку и по имени класса, мы можем сразу понять, что происходит в скрипте транзакции.

Рекомендуемая структура сценария транзакции

  • Метод инициализации с входящими аргументами.
  • Одиночный общественный метод, который запускает действие.
  • Отключите с успехом? и либо полезная нагрузка, либо ошибка в результате. (Этот предмет желательно, но не требуется)

Когда использовать сценарии транзакции

  • Действие сложно
  • Действие включает несколько моделей
  • Используя внутренние услуги
  • Когда вы собираетесь добавить обратный вызов ActiveRecord, но только для одного случая

Плюсы использования сценариев транзакции

  • Контроллер не имеет дело с бизнес-логикой
  • Код может быть повторно использован без дублирования
  • Проще тестировать, репродукция тестовой среды не сложно
  • Структура приложений становится очистителем и легче поддерживать

Оригинальный пост: https://jtway.co/how-to-use-a-transaction-script-aka-service-objects-in-ruby-on-rails-simple-example-hample-61b7e228942.

Оригинал: “https://dev.to/jetthoughts/how-to-use-a-transaction-script-aka-service-objects-in-ruby-on-rails-simple-example-3ll8”