Пролог
Наверное всем веб (а может и не только веб) разработчикам рано или поздно приходилось сталкиваться с такой проблемой как параметры пользователя .
То, что я имею в виду, легче всего показать на картинке.
Под опциями мы подразумеваем чекбоксы (то есть опция либо присутствует, либо нет).
Обычно таких вариантов не слишком много, около 2-10. Обычно они указываются при регистрации и/или редактировании профиля.
Постановка задачи По мере развития проекта, как правило, количество этих настроек (и самих настроек) может меняться, поэтому было бы неплохо реализовать механизм этих опций так, чтобы их добавление/изменение/удаление было максимально простым, изменяя при этом как можно меньше кода.
Я расскажу вам, как решить эту проблему и как я решил ее в рамках Ruby on Rails. Варианты реализации Вообще, я обычно задаю этот вопрос на собеседованиях; Я слышал самые разные ответы.
Один из них – использовать два стола : один для опций, другой для подключения пользовательских опций (есть запись, значит есть галочка в форме).
Преимущества:
- Список редактируемых опций
- соедините таблицы, чтобы узнать, установлена ли эта опция
- нетривиальный код во представлении
<%= f.check_box :send_mail_on_friend_request %>Конечно, это можно реализовать, но код в модели не будет тривиальным.
Другой вариант — использовать для опций один столбец — текст, в котором опции хранятся в сериализованном виде.
class User serialize :options, Hash endВ этом примере непонятно, какие опции могут быть у пользователя, давайте улучшим:
class User OPTION_1 = :key_1 OPTION_2 = :key_2 serialize :options, Hash def option_1=(value) self.options[:key_1] = value end def option_2=(value) self.options[:key_2] = value end def option_1 self.options[:key_1] end def option_2 self.options[:key_2] end endУже понятнее, но методов слишком много: а если вариантов 20? Define_method прекрасно решает эту проблему (пример его использования будет ниже).
Но все же давайте подумаем: ведь опция - это всего лишь чекбокс, совсем чуть-чуть - либо установлен, либо нет (да, прямо как женская интуиция :), зачем сериализовать, десериализовать? Может быть, можно сделать проще? Моя реализация Давайте подумаем, сколько таких вариантов может быть? Думаю максимум 10, ну 20, больше пользователь не заполнит. Что, если вы сохраните опционы как обычный номер? Неплохая идея, просто надо запомнить, как работать с битами:
class User < ActiveRecord::Base NOTIFY_ON_MAIL = 0b0001 NOTIFY_ON_WALL_POST = 0b0010 NOTIFY_ON_FRIEND_REQUEST = 0b0100 NOTIFY_ON_COMMENT_ANSWER = 0b1000 def notify_on_mail self.options & NOTIFY_ON_MAIL != 0 end def notify_on_mail=(value) if value != "0" self.options |= const else self.options &= ~const end end endТак хорошо.
Теперь вы можете обобщить любое количество вариантов:
class User < ActiveRecord::Base NOTIFY_ON_MAIL = 0b0001 NOTIFY_ON_WALL_POST = 0b0010 NOTIFY_ON_FRIEND_REQUEST = 0b0100 NOTIFY_ON_COMMENT_ANSWER = 0b1000 [NOTIFY_ON_MAIL, NOTIFY_ON_WALL_POST, NOTIFY_ON_FRIEND_REQUEST, NOTIFY_ON_COMMENT_ANSWER].Теперь, чтобы добавить новую опцию, вам нужно изменить всего две строки.each do |notifer| const = self.const_get(notifer) define_method notifer.downcase.to_sym do (mail_options & const) != 0 end define_method "#{notifer.downcase}=".
to_sym do |flag| if flag != "0" self.mail_options |= const else self.mail_options &= ~const end end end end
Хм, а что если свести все к одному? Результат:
class User < ActiveRecord::Base NOTIFY_ON_MAIL = 0b0001 NOTIFY_ON_WALL_POST = 0b0010 NOTIFY_ON_FRIEND_REQUEST = 0b0100 NOTIFY_ON_COMMENT_ANSWER = 0b1000 constants.grep(/^NOTIFY_/).Поля для представлений также можно генерировать в цикле.each do |notifer| const = self.const_get(notifer) define_method notifer.downcase.to_sym do (mail_options & const) != 0 end define_method "#{notifer.downcase}=".
to_sym do |flag| if flag != "0" self.mail_options |= const else self.mail_options &= ~const end end end end
Надеюсь, эта небольшая заметка натолкнула вас на некоторые идеи :) Всего вам доброго! Теги: #ruby #ruby на рельсах #опции #ruby на рельсах
-
Плюсы И Минусы Limewire
19 Oct, 24 -
Интернет Без Проводов? Конечно!
19 Oct, 24 -
Восстановление Зрения
19 Oct, 24 -
Какими Проектами Вы Управляете?
19 Oct, 24 -
Научитесь Создавать Приложения На F#.
19 Oct, 24