考虑一个简单的Rails脚手架应用程序,其中包含一个表单,用于通过“保存”按钮将记录添加到数据库中。在“创建”操作之后,控制器重定向到“显示”操作,用户可以使用“编辑”链接编辑刚刚插入的记录。到目前为止,这么简单。
但是,如果用户在创建记录后使用浏览器的后退按钮返回“新”操作,则浏览器会显示包含用户刚刚输入的值的表单。现在他改变了一些值并再次按下“保存”。他认为这会改变记录,但当然这会创造一个新记录。
防止此类重复条目的首选方法是什么?我正在寻找一个通用的解决方案,可能基于cookie或JavaScript。
答案 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| %>