Как лучше всего хранить глобальные настройки приложения в приложении Rails?

Я хочу обрабатывать два типа глобальных параметров конфигурации:

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

Как лучше всего сохранить эти настройки? База данных, конфигурационный файл, жестко запрограммированный в исходниках, ...?


person Daniel Rikowski    schedule 11.10.2009    source источник


Ответы (4)


Для обоих случаев БД. Вы собираетесь использовать одни и те же структуры для нескольких людей/продуктов, так что это имеет смысл. Также это позволяет вам что-то менять без перезапуска сервера.

В прошлом я справлялся с этим следующим образом: для настроек, специфичных для пользователя, я создал модель/таблицу UserSettings, которая имеет отношение «один к одному» с пользователем. Причина этого в том, что большинство моих операций с участием пользователей не требуют загрузки этих настроек, поэтому они включаются в пользовательские загрузки из базы данных только тогда, когда они мне нужны.

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

Что касается настроек, специфичных для продукта, это зависит от того, как вы это делаете. И есть несколько способов интерпретировать ваш вопрос.

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

Я бы использовал продукт «один ко многим» для установления отношений. Таблица настроек будет чем-то упрощенным (product_id, setting_name, setting_default_value, allow_user_change)

Это делает ряд вещей. Это позволяет вам иметь переменный список настроек для разных продуктов (идеально подходит для случая, когда вы предлагаете много разных продуктов вместо разных уровней доступа к услугам). Он также позволяет вам определить, какие настройки пользователь может/не может изменить, и указать значения для этого типа продукта. Это можно изменить в режиме администратора без перезапуска приложения. Он также не привязан к пользовательским настройкам, до такой степени, что если у пользователя нет настроек, перечисленных в product_settings, проблем не возникнет.

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

Вам также придется написать проверки, чтобы гарантировать, что пользователь не изменит настройку, которую их продукт не может изменить. Вам также придется написать вспомогательные методы для объединения настроек со стороны продукта и пользователя.

person EmFi    schedule 11.10.2009

class Flag < ActiveRecord::Base
  # id, user_id, name, value (serialized probably)

  belongs_to :user

  DEFAULTS = {
    "newsletter" => false
  }

  def self.lookup(user, flag)
    # Please involve memcached here
    case flag
    when "ssl_enabled"
      # Check if user has paid for sufficient access to SSL
      return false
    else
      stored_flag = self.find_by_user_id_and_name(user.id, flag)
      if stored_flag
        return stored_flag.value
      else
        return DEFAULTS[flag]
      end
    end
  end
end

class User < ActiveRecord::Base
  has_many :flags

  def flag(name)
    return Flag.lookup(self, name)
  end
end

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

person Bob Aman    schedule 12.10.2009

Вот мой опыт работы с подобными вещами: не переопределять поведение.

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

Хм... Существуют общесистемные настройки, которые могут быть изменены пользователями (или продуктами) или не изменены. Привет! Я знаю это! Это состав!

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

Пока вы не добавите параметр в одну таблицу, а не в другую.

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

И тогда ты поймешь:

Эй, я отслеживаю все эти настройки как минимум в двух разных местах. Это кажется глупым.

И ты будешь прав.

Так да. Держите настройки в БД, но отдельно для каждого пользователя или продукта. Используйте интеллектуальные значения по умолчанию при создании строк, и это сделает все красиво и просто.

person Mando Escamilla    schedule 11.10.2009
comment
Вы сделали всевозможные предположения о том, что он думает и как он собирается реализовать это, но его фактический вопрос был: Как лучше всего хранить эти настройки? Ни одно из ваших предположений не имеет смысла в этом контексте. Я не думаю, что это вполне можно назвать соломенным человеком, но я не уверен, как еще это назвать. - person Bob Aman; 12.10.2009

Для первого вида настроек я бы оставил их в модели User (таблица Users).

Второй тип настроек снова будет обращаться к базе данных. Например, если у пользователя была бесплатная учетная запись, она каким-то образом сохранялась в базе данных. Я хотел бы иметь несколько помощников в приложении, например, «бесплатно?» или "коммерческий?". Эти помощники могут узнать, верны они или нет, запрашивая текущую подключенную модель пользователя/учетной записи. Затем вы можете использовать эти помощники в разных частях вашего приложения, чтобы решить, показывать или скрывать определенные функции.

person Petros    schedule 11.10.2009
comment
Для этого вам придется провести денормализацию. Вероятно, в виде сериализованного поля настроек. Не обязательно плохо, но денормализация — это всегда компромисс. - person Bob Aman; 12.10.2009