Интерпретация логики приложений 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 кто-то уже сделал кучу работы над этим планом:)