Я думаю, что вы пытаетесь поместить свою проверку не в то место, и ваша схема может быть немного скорректирована.
Если кто-то вводит 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
.
Нет правила, согласно которому ваш пользовательский интерфейс должен бытьпростой редактор для ваших свойств модели данных и тесное связывание этих двух типов часто является ошибкой (невероятно распространенная ошибка, но, тем не менее, ошибка).