Rails:由于按下后退按钮而防止重复插入并再次保存

时间:2011-01-11 12:47:19

标签: ruby-on-rails browser controller crud

考虑一个简单的Rails脚手架应用程序,其中包含一个表单,用于通过“保存”按钮将记录添加到数据库中。在“创建”操作之后,控制器重定向到“显示”操作,用户可以使用“编辑”链接编辑刚刚插入的记录。到目前为止,这么简单。

但是,如果用户在创建记录后使用浏览器的后退按钮返回“新”操作,则浏览器会显示包含用户刚刚输入的值的表单。现在他改变了一些值并再次按下“保存”。他认为这会改变记录,但当然这会创造一个新记录。

防止此类重复条目的首选方法是什么?我正在寻找一个通用的解决方案,可能基于cookie或JavaScript。

8 个答案:

答案 0 :(得分:7)

经过一些调查后,我发现了一种基于cookie的合适解决方案。这是:

在控制器的“新”操作中,生成具有当前时间的时间戳,并将其作为隐藏字段呈现在窗体中。当用户提交表单时,此时间戳将返回到控制器的“创建”操作。创建记录后,此时间戳存储在会话cookie中。如果用户通过浏览器的后退按钮返回“新”表单,则会获得陈旧形式,这意味着其时间戳早于存储在cookie中的时间戳。在创建记录之前检查这一点并导致出现错误消息。

这是控制器代码:

def new
  @post = Post.new
  @stale_form_check_timestamp = Time.now.to_i
end

def create
  @post = Post.new(params[:post])

  if session[:last_created_at].to_i > params[:timestamp].to_i
    flash[:error] = 'This form is stale!'
    render 'new'
  else
    @post.save!
    @stale_form_check_timestamp = Time.now.to_i
    session[:last_created_at] = @stale_form_check_timestamp
  end
end

这里是表单代码:

- form_for @post do |f|
  = tag :input, :type => 'hidden', :name => 'timestamp', :value => @stale_form_check_timestamp
  = f.input :some_field
  = .......

答案 1 :(得分:4)

当我遇到同样的问题时,我创造了这个解决它的小宝石。当用户回击时,他被重定向到记录的edit_path,而不是返回new_path

https://github.com/yossi-shasho/redirect_on_back

您可以执行以下操作:

def create
  @user = User.new(params[:user])
  if result = @user.save
    redirect_on_back_to edit_user_path(@user) # If user hits 'back' he'll be redirected to edit_user_path
    redirect_to @user
  end
end

答案 2 :(得分:2)

您的模型验证将确保电子邮件地址等内容是独一无二的,但我认为这更多地是关于可用性和体验,而不是其他任何内容。

假设您正在谈论帐户创建表单。首先,您的表单提交按钮应该是“创建帐户”,而不仅仅是“提交”。然后,根据是否成功,显示消息,例如“帐户已成功创建”或“创建帐户时出错”。如果用户看到此消息,他们将知道发生了什么。

当然,你不能阻止别人按下后退按钮并再次进入,但你应该为大多数用例设计。如果他们碰巧回击,他们会看到显示“创建帐户”的按钮。您可能应该在页面上显示“请注册新帐户以开始使用”的其他文字。

只需我0.02美元。

答案 3 :(得分:2)

会话或cookie可能会导致副作用。

我完全同意:如果有办法验证您的模型,这是防止重复记录的最安全方法。

你仍然可以做两件事。阻止浏览器缓存:当用户clicks on the back button时,表单中的字段将显示为空。单击时禁用“创建”按钮。

= f.submit "Create", :disable_with => "Processing..."

当您的用户按下后退按钮时,该按钮将被禁用。

答案 4 :(得分:0)

您可以使用验证器确保不插入重复值。在这种情况下validates_uniqueness_of :field

例如,如果您想阻止用户使用相同的电子邮件地址,则可以在用户模型中添加以下代码。

validates_uniqueness_of :email

这将检查列中是否存在与您尝试惰性的条目相同的任何先前条目。 祝你好运

答案 5 :(得分:0)

基于@Georg Ledermann回答我做了一小段代码,如果用户回击然后点击创建,则重定向到编辑路径。

#objects_controller.rb
def new
    @object = Object.new
    @stale_form_check = Time.now.to_i
end

def create
    @object = Object.new(object_params)
    #function defined in application_controller.rb
    redirect_to_on_back_and_create(@object)
end

#application_controller.rb
private
def redirect_to_on_back_and_create(object)
    if session[:last_stale].present? and session[:last_stale_id].present? and session[:last_stale].to_i == params[:stale_form_check].to_i 
        redirect_to edit_polymorphic_path(object.class.find(session[:last_stale_id].to_i)), alert: "Este #{object.model_name.human} ya ha sido creado, puedes editarlo a continuación"
    else 
        if object.save
            session[:last_stale] = params[:stale_form_check].to_i
            session[:last_stale_id] = object.id
            redirect_to object, notice: "#{object.model_name.human} Creado con éxito"
        else
            render :new 
        end
    end
end

最后将@stale_form_check参数添加到表单

<%= hidden_field_tag :stale_form_check, @stale_form_check %>

您总是可以在需要的地方抽象出这种方法,但是如果您在许多地方需要这种行为,这样就可以避免项目中的大量重复

希望它有助于下一个,我曾经使用redirect_on_back gem,但这次对我来说不起作用,这个gem使用的_usec param总是被重置,所以它无法在每次比较什么时候需要

答案 6 :(得分:0)

这是适合我的东西。

您需要做两件事:在控制器中创建一个方法,并在“create”方法下的同一控制器中添加条件语句。

1)您的方法应该从该用户返回该对象的总数。

EX:

def用户  current_user.object.count 端

2)在'create'方法中添加条件语句。

实施例

def创建   @object = Object.create(object_params)      @ object.save if user == 0      redirect_to x_path 端

我希望这有帮助!

答案 7 :(得分:0)

像这样在您的html: { autocomplete: "off" }中添加form_for

<%= form_for @object, url: xxx_path, html: { autocomplete: "off" } do |f| %>