Интерпретация логики приложений Rails

Я разрабатываю приложение rails, которое будет иметь отдельные экземпляры, запущенные в разных странах. Интернационализация заботится о языковых проблемах, но когда есть некоторые незначительные логические изменения, я не уверен, как подойти. Одним из примеров может быть способ оплаты - в каждой стране пользователям будут представлены разные варианты с различными интеграциями. Другими примерами могут быть зарплаты - налоги и социальные ценные бумаги полностью отличаются от страны к стране, поэтому нам нужно учитывать это.

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

Решение, о котором я сейчас думаю, состоит в том, чтобы иметь другую среду для каждой страны - "production_germany", "production_france" и т.д., и в зависимости от этого загружать другой файл yml со всеми необходимыми переменными, которые я буду нуждающихся в этой стране. Затем создайте класс "Менеджер", который будет принимать решения о том, какие специальные классы загружать и какие вещи показывать на представлениях (везде, где есть различия). Например, у меня могут быть классы расчета зарплаты для германии в "зарплата/калькуляция/де" и для франции в "зарплата/калькуляция/fr" и загружать только те, которые мне нужны.

Каким будет ваше решение?

Ответ 1

Я бы обработал как можно больше, используя Rails 'I18n. Если вы еще этого не сделали, посмотрите также rails-i18n.

Для ваших особых случаев, которые не обрабатываются Rails, я бы сделал это, как Rails. Например, в вашем config/locales у вас может быть какая-то конфигурация для налогов в стране:

en:
  taxes:
    name: Tax
    rate: 0.065
de:
  taxes:
    name: USt
    rate: 0.19

Затем вы пишете модуль TaxesHelper, который будет использовать информацию из файла локали для отображения ставки налога. Взгляните на пакет Rails NumberHelper.

Если вы действительно делаете расчеты с чем-то вроде ставок налогов, я бы сохранил фактор в модели, где вы делаете расчет. Таким образом, ваши расчеты не будут перепутаны при изменении налоговой ставки. Скажем, у вас есть следующая модель:

class Invoice < ActiveRecord::Base
  # Injected by AR
  # attr_accessor :net_price
  # attr_accessor :tax_rate
  def gross_price
    net_price * tax_rate
  end

  before_create do
    tax_rate = I18n.t(:rate, scope: [ :taxes ]).to_f
  end
end

Таким образом, ваша валовая цена не изменится для постоянных счетов-фактур после изменения ставки налога в конкретной стране.

Ответ 2

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

когда вам нужно больше бизнес-логики, тогда все становится более сложным, и нет решения 1-размер-подходит для всех, просто убедитесь, что знаете инструменты в вашем распоряжении и убедитесь, что вы поместили правильный, и вот еще один, что кажется немного недоиспользуемым в рубиновом сообществе:

Включение зависимостей

Например: http://solnic.eu/2013/12/17/the-world-needs-another-post-about-dependency-injection-in-ruby.html

Этот шаблон обычно хорош для управления шлюзами поставщика платежей, например

class Transaction < ActiveRecord::Base
  def gateway_class
    I18n.t(:class_name, scope: [ :payment_provider ]).constantize
  end
  def gateway
    @gateway ||= gateway_class.new(self)
  end
end

I18n параметризует класс поставщика платежей в зависимости от страны:

en:
  payment_provider:
    class_name: PaymentProvider
de:
  payment_provider:
    class_name: AnotherPaymentProvider

и вы убедитесь, что класс поставщика платежей отвечает на один и тот же публичный API, поэтому для всего приложения нет необходимости знать, какой поставщик платежей используется, а именно, что интерфейс поставщика платежей сопряжен.

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

Собственно, посмотрите здесь: https://github.com/activemerchant/active_merchant кто-то уже сделал кучу работы над этим планом:)