Логическое значение против Перечисление против Отметить

#ruby #sinatra #datamapper #ruby-datamapper

#ruby #синатра #datamapper #ruby-datamapper

Вопрос:

Я работаю над веб-сайтом, который позволяет пользователям входить в систему. У всех пользователей есть 1 учетная запись, у учетной записи может быть много заказов. Пользователь может быть клиентом, работником или менеджером. Клиент никогда не является ни работником, ни менеджером. менеджер также является работником. Я хотел бы представить дополнительные разделы страниц / параметров навигации в зависимости от типа пользователя, вошедшего в систему.

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

 class User
  include DataMapper::Resource
  # ...
  # various properties
  # ...
  property :client, Boolean
  property :worker, Boolean
  property :manager, Boolean
end
  

И затем я использую фильтр before для проверки типа пользователя и установки результата в качестве переменной.

 before do
  @user = session[:user]
  if @user.client?
    @ura = 'client'
  elsif @user.worker?
    @ura = 'worker'
  elseif @user.manager?
    @ura = 'manager'
  end
end
  

Тогда, по моим представлениям, у меня есть @ura, с которым можно поиграть. Мне кажется, что это уже вызовет у меня проблемы для менеджеров, потому что @ura должен быть и рабочим, и менеджером. Я мог бы использовать некоторые или в моих представлениях, но я думаю, что лучшим решением было бы установить тип пользователя в качестве перечисления или флага. Но я не совсем понимаю, как использовать это в моем процессе.

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

Ответ №1:

Я не уверен, но, возможно, лучшим решением будет массив:

 class User ....
   def getRoles
      roles = Array.new
      roles << "client" if self.client? 
      roles << "manager" if self.manager? 
      roles << "worker" if self.worker? 
      roles
   end
end

before do
  @user = session[:user]
  if(@user.getRoles.index("manager") != nil)
    ...
  

Комментарии:

1.Это похоже на то, о чем я думал. Кажется, что использование чего-то подобного property :role, Enum[ :client, :worker, :manager ] в основном дало бы мне то, что вы описали в одной строке. Я понимаю, что что-то может быть только одним перечислением за раз. (т. е.. user.role = :worker перезаписало бы любое текущее значение:role)В то время как a Flag может содержать любое из определенных значений в качестве свойства. Я понимаю Enum , но я не понимаю взаимосвязи Flag (т.е. Как можно было бы установить и отменить определенные значения Flag ? * (могут ли они быть отключены после установки?) *)

2. В идеале я хотел бы иметь что-то вроде .client? и иметь этот возврат true или false . Так что я могу сделать что-то вроде if @ura.client? . (Я в порядке с тем, чтобы самостоятельно разобраться с кодом для этого, я просто пытаюсь разобраться в наилучшем способе представления этой информации.)

Ответ №2:

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

Итак, всего десять лет спустя, хотя я больше не использую DataMapper регулярно, он — то, как я решил бы это сейчас;

В то время я не до конца понимал разницу между аутентификацией и авторизацией в отношении пользователей Role в системе.

 class User
  include DataMapper::Resource
  ...
  properties
  ...
  property :role, Enum[ :client, :worker, :manager ]
end

class Employee < User
  include DataMapper::Resource
  ...
   more properties
end
  

Таким образом, все пользователи могут иметь то, что им нужно, сотрудники могут быть дополнительно разделены на Worker amp; Manager . затем вы можете поместить соответствующие проверки в соответствующую модель. Больше исходного кода, но более удобен в обслуживании и более прост в масштабировании, просто добавьте новую роль в User Enum и соответствующий класс.

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