Pull to refresh

Comments 32

UFO landed and left these words here
А что со скоростью работы? Мы же 1 раз создаем все методы и пробегаем по константам
А при чем тут скорость?)
Ты всерьез считаешь что читаемость кода проекта важнее куда менее важна чем + 20ms на выборку?)
Оочень приятно при 20+ настройках хранить их в User.constants
это не очевидно, и дело не в программистcких способностях кого — либо, а просто плохо читаемо.
class U < AR::Base
has_many :preferences, куда проще
end
хочется еще больше простоты, не изобретай велосипеды, а посмотри на тот же gem preferences )
Чистейшая «джедайская» предварительная оптимизация :)
Спасибо, я когда-то уже видел подобную реализацию, но в PHP.
А если вам придется делать выборку по всем пользователям, по которым у вас установлен тот или иной флаг — то запросу в базе придется обрабатывать все строки в таблице, если вы будете хранить битовые маски.
Судя по приведенным примерам опций это просто необходимо будет делать.
Поправьте меня, если я не прав.

Взведенную опцию можно выбирать, с помощью LIKE, как вхождение в строку. Естественно, колонка у вас будет строкой, что не очень хорошо.

Если нас интерисует, допустим, NOTIFY_ON_MAIL, то получается что нас интерисуют пользователи с значением «options» в базе с еденичкой в первом разряде.
> SELECT * FROM users WHERE users.options LIKE "???1";


А вообще, отдельная таблица options со связью к users, как has_one/belongs_to самое лучшее решение.

Разве это сильно сложно? По крайней мере не сложнее, чем добавить еще один разряд в ваше двоичное поле.
add_column :options, :notify_on_mail, :booleanб :default => :false

А вот выборки будут в сто раз лучше. И не нужно никаких дополнительных define_method и остальных плясок с бубном.
Мне тоже показалась булева колонка втаблице с юзерами будет без всяких извращений.
Причем автор пишет «чтобы добавлять/изменять/удалять их было максимально просто, изменив при этом как можно меньше кода»
Меня это всегда удивляло, ведь по-идее каждая опция несет некоторую смысловую нагрузку — логику обработки ведь все равно писать.
ALTER TABLE ADD COLUMN… это < 0,01% от того кода что придется написать, вообщем я за булевские колонки в виде таблицы опций one-to-one к таблице пользователей
Колонка не string, а unsigned int.

Ну и запрос не
SELECT * FROM users WHERE users.options LIKE "???1";
а
SELECT * FROM users WHERE (users.options & 1)
Хотя от полного посмотре таблицы это не избавляет.
а потом настроек становится столько, что они начинают не влезать в unsigned int (=
bigint 64 бита. 64 настройки, куда уж больше то? )
ну если субд позволяет (=если постгрес, а не мускл), то можно просто достраивать индексы конкретно по нужным опциям, тогда скорость выборки не будет уступать другим вариантам.

это конечно же не значит, что я считаю хранение юзерских настроек в битмапе хорошей идеей.
В рамках моего проекта [галочки оттуда] этого делать не нужно. После допустим добавления комментария проверяем, взведен ли флаг «оповещать о комментариях» и если да — делаем оповещение. Если нужна выборка по флагам, тогда придется придумать что-нибудь другое.
Вот буду я после вас проект доделывать (гипотетическое предположение), буду сильно ругаться на столь неочевидное решение.

Ваш вариант полезен в чисто академических целях. На практике лучше применять стандарнтые решения.
Предполагаю, что рассмотренный выход из ситуации в перспективе породит множество хлопот.
Я его сюда как раз разместил для академических целей. Чтобы люди рассказали как сделали бы они. Как говорится для расширения кругозора [я нигде не утверждал что мое решение единственно приемлимое и правильное]. Что почасти моего проекта, если для вас мое решение не очевидно, то скорей всего вы просто не подходите для доделки моего проекта :)
>>скорей всего вы просто не подходите для доделки моего проекта :)

Упаси Б-Г!!!
Мы такое через method_missing делали, но у нас правда постановка задачи была несколько иная — общие настройки сайта, хотя пара движений напильником и запросто делается и для юзеров.
github.com/jaralex/SettingTest
Всё-таки method_missing хуже, чем define_method, т.к. нужный метод будет при каждом вызове искаться.
вообщем то на method_missing построено очень много Rails Magick, не думаю, что это очень критично. Зато гораздо более читабельно.
Разве нельзя для этих целей пользоваться миграциями?
class User < ActiveRecord::Base

  OPTIONS = [:option1, :option2, :option3]

  OPTIONS.each_index do |index|
    option = OPTIONS[index]
    const = 1 << index

    define_method(option) do
      self.options & const) != 0
    end

    define_method("#{option}=") do |value|
      if value != "0"
        self.options |= const
      else
        self.options &= ~const
      end
    end
  end
end

мне почемуто подумалось, что так удобней будет. Меньше возможностей запутаться в нулях и единицах, при создании опций.
можно сделать класс Option, и отношение one-to-many, User->Options. и по списку ссылок на Options'ы считать.
Очередной раз убеждаюсь, что создатель руби очень любил Python
Это ирония? Anyway, питон в числе языков повлиявших на Мацумото перед реализацией Руби.
Действительно, зачем изобретать велосипеды. Мы в проекте использовали FlagShihTzu — отличная библиотека.
+ 1, чтобы остальные обратили внимание на твой пост
ps. кармы нема
Sign up to leave a comment.

Articles