Rails 3 before_filter设置并检查布尔值| paperchase /寻宝游戏

时间:2011-06-14 17:35:37

标签: ruby ruby-on-rails-3 qr-code before-filter

我正在开发一个纸质/寻宝移动网络应用程序。我有基本身份验证,如果用户扫描以下任何代码,他将被定向到sign_up页面。到目前为止一切正常但是这里有一个棘手的部分:

我有10个QR码,每个QR码代表一个URL。

  1. QR码ID:1网址:http://paperchase.heroku.com/qrs/4975
  2. QR码ID:2网址:http://paperchase.heroku.com/qrs/2368
  3. QR码ID:3网址:http://paperchase.heroku.com/qrs/2317
  4. QR码ID:4网址:http://paperchase.heroku.com/qrs/2369
  5. QR码ID:5网址:http://paperchase.heroku.com/qrs/6247
  6. QR码ID:6网址:http://paperchase.heroku.com/qrs/1493
  7. QR码ID:7网址:http://paperchase.heroku.com/qrs/1759
  8. QR码ID:8网址:http://paperchase.heroku.com/qrs/4278
  9. QR码ID:9网址:http://paperchase.heroku.com/qrs/8912
  10. QR码ID:10网址:http://paperchase.heroku.com/qrs/5346
  11. 现在我希望用户按所示顺序扫描每个代码。如果他扫描代码1,他将找到代码2的指示,如果他扫描代码2,他将找到代码3的指示,依此类推。但是现在可以跳过代码,例如您可以在代码1之后扫描代码10并获胜。

    我提出的解决方案:

    所有QR码均设为false。如果扫描QR-Code 1,它将被设置为true并且您可以扫描QR-Code 2.如果您现在想要扫描QR-Code 5,它会将您重定向到root_path,因为QR-Code 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码是否设置为真)但我不知道它是怎么回事应该看起来像。

    提前致谢

2 个答案:

答案 0 :(得分:0)

我认为您正在尝试将验证放在错误的位置,并且您的架构可能会进行一些调整。

如果有人正在输入QR4,你真的关心他们已经通过QR3输入了QR1或者你真的只关心他们输入的最后一个是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_qrself.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

然后以通常的方式将该关联与您的用户和QrCode模型相关联。

另请注意,此结构只需要几个简单的修改,以允许多个“纸张追逐”同时运行。您只需将用户模型中的一些内容移至user_paper_chases模型,并将paper_chase参数添加到User#add_code

没有规则说你的用户界面必须是你的数据模型属性的简单编辑器,并且紧密绑定这两者通常是一个错误(一个非常常见的错误,但仍然是一个错误)。

答案 1 :(得分:0)

为什么不在模型中存储一个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