Rails - 用户按“返回”键创建对象后,创建重复项

发布于 2024-12-19 13:51:18 字数 705 浏览 1 评论 0原文

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

防止此类事情发生的最佳方法是什么。

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

更新

routes.rb

resources :survey_criteria do
  resources :groups do
    resources :evaluations
  end
end

Survey_criterion.rb

has_many :evaluations

evaluation.rb

belongs_to :survey_criterion
belongs_to :group

有更复杂的关联,但我正在寻找的答案更多,“当用户按下‘后退’按钮时如何处理,修改表单,然后再次单击“创建””。

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

想法?

I'm having a problem where when a user fills out my evaluation form, click "Create", then click the browser's back button, make some edits, and click "Create" again, it's creating duplicate Evaluations.

What is the best way to prevent something like this happening.

Only ONE evaluation should exist for each survey_criterion on creation. I don't want the user to lose any data they enter after hitting the back button, filling out the form with new stuff, and clicking "Create" again.

UPDATE

routes.rb

resources :survey_criteria do
  resources :groups do
    resources :evaluations
  end
end

survey_criterion.rb

has_many :evaluations

evaluation.rb

belongs_to :survey_criterion
belongs_to :group

There are more complicated associations, but the answer I'm looking for is more, "how does one handle it when users press the 'Back' button, modify the form, then click Create again".

I want it to update the one that was automatically created I think in this instance, and not throw an error to the user. I know I could add a validation that would error out, but I want this to be invisible to the user I think.

Thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

独自←快乐 2024-12-26 13:51:18

最简单的解决方案是更改 create 操作,该操作应该像这样的伪代码一样工作:

def create
  # ...
  if evaluation_exists?
    update_evaluation(params[:evaluation])
  else
    create_evaluation(params[:evaluation])
  end
  # ...
end

至于您的问题“当用户按下“后退”按钮时如何处理它,请修改表单,然后再次单击“创建””,然后我使用一些随机令牌(短字符串)作为表单中的隐藏字段放置。

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

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

def create
  token = params[:token]
  session[:tokens] ||= []
  if session[:tokens].include? token
    render_the_form_again( "You have already created the object. Want another?" )
  else
    create_the_object
    session[:tokens] << token
  end
  # ...
end

The simplest solution, would be to change the create action, which should work like this pseudocode:

def create
  # ...
  if evaluation_exists?
    update_evaluation(params[:evaluation])
  else
    create_evaluation(params[:evaluation])
  end
  # ...
end

As for Your question "how does one handle it when users press the 'Back' button, modify the form, then click Create again", then I use some random token (a short string) placed as a hidden field in the form.

When the create-request comes, I check whether this token is already stored in the session. If it is not, then I create the object, and add that token to the list of used ones. If the token is already present in the session, I know that user has just resubmitted the form, and I can act accordingly. Usually I ask him whether another object should be created. In the session I store usually not more that 3-5 tokens.

It looks like this (yes, that's just an illustration):

def create
  token = params[:token]
  session[:tokens] ||= []
  if session[:tokens].include? token
    render_the_form_again( "You have already created the object. Want another?" )
  else
    create_the_object
    session[:tokens] << token
  end
  # ...
end
幽梦紫曦~ 2024-12-26 13:51:18

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

validates_uniqueness_of :survey_criterion_id

假设 SurveyCriterion 拥有与您的评估关联的外键。

In your Evaluation model, add this line :

validates_uniqueness_of :survey_criterion_id

This is assuming that SurveyCriterion holds the foreign key that associates with your Evaluation.

忆沫 2024-12-26 13:51:18

您还可以做两件事:

  1. 防止浏览器缓存。
  2. 使用 :disable_with => 禁用创建按钮“处理”选项。

这里也讨论了:https://stackoverflow.com/a/12112007/553371

You can also do 2 things :

  1. Prevent the browser cache.
  2. Disable the Create button with :disable_with => "Processing" option.

It is discussed here too: https://stackoverflow.com/a/12112007/553371

瞳孔里扚悲伤 2024-12-26 13:51:18

一种不太优雅但更通用的方法是使用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的History API。使用 history.js 项目可以通过回退来完成类似的事情

A less elegant way but more generic way to do this is to use history.pushState. On the page after create:

$(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);
  }

})

This example uses HTML5's History API. A similar thing can be done with fallback using the history.js project

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文