Rails 3 before_filter установка и проверка логических значений | Paperchase / игра для поиска сокровищ - PullRequest
1 голос
/ 14 июня 2011

Я работаю над мобильным веб-приложением paperchase / treasure hunt. У меня есть базовая аутентификация, если пользователь сканирует любой из следующих кодов, он будет направлен на страницу регистрации. Пока все работает нормально, но тут есть сложная часть:

У меня есть 10 QR-кодов, каждый из которых представляет один URL.

  1. ID QR-кода: 1 URL: http://paperchase.heroku.com/qrs/4975
  2. ID QR-кода: 2 URL: http://paperchase.heroku.com/qrs/2368
  3. ID QR-кода: 3 URL: http://paperchase.heroku.com/qrs/2317
  4. ID QR-кода: 4 URL: http://paperchase.heroku.com/qrs/2369
  5. ID QR-кода: 5 URL: http://paperchase.heroku.com/qrs/6247
  6. ID QR-кода: 6 URL: http://paperchase.heroku.com/qrs/1493
  7. ID QR-кода: 7 URL: http://paperchase.heroku.com/qrs/1759
  8. ID QR-кода: 8 URL: http://paperchase.heroku.com/qrs/4278
  9. ID QR-кода: 9 URL: http://paperchase.heroku.com/qrs/8912
  10. ID QR-кода: 10 URL: http://paperchase.heroku.com/qrs/5346

Теперь я хочу, чтобы пользователь сканировал каждый код в указанном порядке. Если он сканирует код 1, он найдет указания для кода 2, если он сканирует код 2, он найдет указания для кода 3 и так далее. Но сейчас можно пропустить коды, например, Вы можете отсканировать код 10 после кода 1 и выиграть.

Решение, которое я придумал:

Все QR-коды имеют значение false. Если вы сканируете QR-код 1, для него будет установлено значение true, и вы сможете сканировать QR-код 2. Если теперь вы хотите отсканировать QR-код 5, он перенаправит вас на путь root_path, поскольку QR-код 4 имеет значение false.

Это часть моей модели пользователя:

  ...
  t.boolean :qr_01, :default => false
  t.boolean :qr_02, :default => false
  t.boolean :qr_03, :default => false
  t.boolean :qr_04, :default => false
  ...

Теперь я думаю, что мне нужно написать что-то вроде before_filter с логикой (установка QR-кодов в true, проверка, установлены ли все предыдущие QR-коды в true) Но я понятия не имею, как это должно выглядеть как.

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 14 июня 2011

Почему бы просто не сохранить одно поле int в вашей модели?

Например, если моя модель пользователя имела

 t.integer :qr_code

Вы можете просто проверить действие вашего контроллера:

def add_qr
  user = User.find_by_id(params[:id])
  if user.qr_code != params[:qr_code]-1
    redirect_to(some_url)
  else
    user.qr_code+=1
    user.save
    #do whatever else you need to do and display view
  end
end
0 голосов
/ 14 июня 2011

Я думаю, что вы пытаетесь поместить свою проверку не в то место, и ваша схема может быть немного скорректирована.

Если кто-то вводит QR4, действительно ли вам важно, чтобы он вводил QR1 черезQR3 уже или вы действительно заботитесь только о том, чтобы последним был введен QR3?В тот момент, когда вводится новый код, действительно важно то, что он следует сразу после последнего;и, чтобы все было согласованно, у вас мог бы быть виртуальный QR0, представляющий состояние «еще не было введено».

В вашей пользовательской модели у вас будет такой метод:

def add_code(qr)
    # Check that qr immediately follows self.last_qr;
    # if it does, then update and save things and
    # continue on; if it doesn't, then raise an
    # exception that says, more or less, "QR Code out
    # of sequence".
end

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

before_create :initialize_qrs
validate :contiguous_qrs

#...

def initialize_qrs
  self.last_qr   = 0
  self.latest_qr = 0
end

def contiguous_qrs
  if(self.last_qr == 0 && self.latest_qr == 0)
    # New user, no worries.
    true
  elsif(self.latest_qr != self.last_qr + 1)
    # Sequence error, your `add_code` method should
    # prevent this from ever happening but, hey, bugs
    # happen and your code shouldn't trust itself any
    # more than it has to.
    false
  end
  true
end

Ваш add_code метод может установить self.last_qr иself.latest_qr пока он выполнял свою другую работу.

Затем в вашем контроллере:

def enter_code
    # Get the code and validate it, leave it in qr
    begin
      current_user.add_code(qr)
    rescue Exception => e
      # Complain and wag your finger at them for cheating
    end
    # Give them instructions for finding the next one,
    # these instructions would, presumably, come from
    # something like "instructions = qr.next_one.instructions".
end

Отслеживание пар (пользователь, QR-код) имеет смысл для целей аудита, но этоДля меня было бы более разумно иметь отдельную модель (в виде таблицы ассоциации) для этого:

create table "user_qr_codes" do |t|
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
  t.integer  "user_id",    :null => false
  t.integer  "qr_code_id", :null => false
end

И затем связать эту связь с вашими моделями User и QrCode обычным способом.

Также обратите внимание, что для этой структуры потребуется всего пара простых модификаций, чтобы можно было одновременно запускать несколько «бумажных погонь».Вам просто нужно переместить пару вещей из вашей пользовательской модели в модель user_paper_chases и добавить параметр paper_chase в User#add_code.

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

...