Ruby on rails 导轨-用户按下';背面';创建对象后,创建重复项

Ruby on rails 导轨-用户按下';背面';创建对象后,创建重复项,ruby-on-rails,ruby-on-rails-3,browser,duplicates,back-button,Ruby On Rails,Ruby On Rails 3,Browser,Duplicates,Back Button,我遇到一个问题,当用户填写我的评估表时,单击“创建”,然后单击浏览器的“后退”按钮,进行一些编辑,然后再次单击“创建”,它将创建重复的评估 防止类似情况发生的最佳方法是什么 创建时,每个调查标准只能有一个评估。我不希望用户在点击后退按钮、用新内容填写表单并再次单击“创建”后丢失他们输入的任何数据 更新 routes.rb resources :survey_criteria do resources :groups do resources :evaluations end en

我遇到一个问题,当用户填写我的评估表时,单击“创建”,然后单击浏览器的“后退”按钮,进行一些编辑,然后再次单击“创建”,它将创建重复的评估

防止类似情况发生的最佳方法是什么

创建时,每个
调查标准
只能有一个
评估
。我不希望用户在点击后退按钮、用新内容填写表单并再次单击“创建”后丢失他们输入的任何数据

更新

routes.rb

resources :survey_criteria do
  resources :groups do
    resources :evaluations
  end
end
调查标准.rb

has_many :evaluations
evaluation.rb

belongs_to :survey_criterion
belongs_to :group
有更复杂的关联,但我要寻找的答案更多,“当用户按下“后退”按钮,修改表单,然后再次单击“创建”时,如何处理它”

我希望它更新我认为在这个实例中自动创建的一个,而不是向用户抛出错误。我知道我可以添加一个会出错的验证,但我想这对用户来说是不可见的


想法?

在您的评估模型中,添加以下行:

validates_uniqueness_of :survey_criterion_id

这是假设SurveyCriterion持有与您的评估相关联的外键。

最简单的解决方案是更改
create
操作,该操作应与以下伪代码类似:

def create
  # ...
  if evaluation_exists?
    update_evaluation(params[:evaluation])
  else
    create_evaluation(params[:evaluation])
  end
  # ...
end
至于你的问题“当用户按下“后退”按钮,修改表单,然后再次单击“创建”时,如何处理它”,然后我使用一些随机标记(一个短字符串)作为表单中的隐藏字段

当create请求到来时,我检查这个令牌是否已经存储在会话中。如果不是,则创建对象,并将该标记添加到已使用标记的列表中。如果令牌已经存在于会话中,我知道用户刚刚重新提交了表单,我可以相应地采取行动。通常我问他是否应该创建另一个对象。在会话中,我存储的令牌通常不超过3-5个

它看起来像这样(是的,这只是一个例子):

def创建
令牌=参数[:令牌]
会话[:令牌]| |=[]
如果会话[:令牌]。是否包括?代币
再次呈现表单(“您已经创建了对象。要另一个吗?”)
其他的
创建\u对象

session[:tokens]一种不那么优雅但更通用的方法是使用
history.pushState
。在创建后的页面上:

$(function(){
  if(history.pushState){
    window.onpopstate = function(event){
      if(window.history.state && window.history.state.previousStep){
        window.location = window.history.state.previousStep;
      }
    }
    window.history.replaceState({ previousStep: '#{edit_resource_url(resource)}'}, document.title, window.location);
    window.history.pushState({}, document.title, window.location);
  }

})

本例使用HTML5的
历史API
。类似的事情也可以通过使用项目进行回退来完成。您还可以做两件事:

  • 阻止浏览器缓存
  • 使用:Disable_with=>“Processing”选项禁用创建按钮

  • 这里也讨论了这一点:

    您能否更具体地说明这两个模型之间关系的性质?关于你的
    创建
    操作,我明天上班时会尝试添加更多信息。谢谢。有关于你的表格的信息也可能有用。您是创建关联的
    评估
    以及新的
    调查标准
    (以嵌套形式),还是以不同的形式创建两者?如果我很了解您想要实现的目标,a应该可以做到这一点,因为点击后退按钮将返回新的
    调查标准
    表单,确保如果再次点击提交,您将尝试创建新的
    调查标准
    ,而不是新的
    评估,它可能比这更复杂一点。我明天回去工作时再谈这个问题。谢谢。谢谢你花时间回答这个问题,它真的帮助我思考这个问题,应该可以满足我的需要。我认为如果有人在创建表单上使用后退按钮,他应该期望每次都创建一个新对象,这只是常识。另一方面,我承认@Arsen7的解决方案对用户更友好。我认为如果有人在他们的创建表单中输入了一个错误,很快就回击了,但没有意识到,修复了他们的输入错误,然后再次单击“创建”,这对他们来说不是“常识”。他们只会感到困惑,为什么它没有做到他们想要的。用户和常识并不完全混合:)这在你所有的控制器中都会很好。
    
    $(function(){
      if(history.pushState){
        window.onpopstate = function(event){
          if(window.history.state && window.history.state.previousStep){
            window.location = window.history.state.previousStep;
          }
        }
        window.history.replaceState({ previousStep: '#{edit_resource_url(resource)}'}, document.title, window.location);
        window.history.pushState({}, document.title, window.location);
      }
    
    })