Rails:由于按下后退按钮而防止重复插入并再次保存
想想一个简单的Rails脚手架应用程序,其中包含一个表单,用于通过“保存”按钮将记录添加到数据库中。 在“创建”操作之后,控制器重定向到“显示”操作,用户可以使用“编辑”链接编辑刚刚插入的记录。 到目前为止,这么简单。
但是,如果用户在创建记录后使用浏览器的后退按钮返回“新”操作,则浏览器会显示包含用户刚刚输入的值的表单。 现在他改变了一些值并再次按下“保存”。 他认为这会改变记录,但当然这会创造一个新记录。
防止此类重复条目的首选方法是什么? 我正在寻找一个通用的解决方案,可能基于cookie或JavaScript。
经过一些调查,我找到了一个基于cookie的合适解决方案。 这里是:
在控制器的“新”操作中,生成具有当前时间的时间戳,并将其作为隐藏字段呈现在表单中。 当用户提交表单时,此时间戳将返回到控制器的“创建”操作。 创建记录后,此时间戳存储在会话cookie中。 如果用户通过浏览器的后退按钮返回“新”表单,则会获得陈旧forms,这意味着其时间戳早于存储在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 = .......
当我遇到同样的问题时,我创造了这个解决它的小gem。 当用户回击时,他被重定向到记录的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
您的模型validation将确保电子邮件地址等内容是独一无二的,但我认为这更多地是关于可用性和体验,而不是其他任何内容。
假设您正在谈论帐户创建表单。 首先,您的表单提交按钮应该说“创建帐户” ,而不仅仅是“提交”。 然后,根据是否成功,显示“帐户已成功创建”或“创建帐户时出错”等消息。 如果用户看到此消息,他们将知道发生了什么。
当然,你不能阻止某人按下后退按钮并再次进入,但你应该为大多数用例设计。 如果他们碰巧回击,他们会看到显示“创建帐户”的按钮。 您可能应该在页面上显示“请注册新帐户以开始使用”的其他文本。
只需我0.02美元。
会话或cookie可能会导致副作用。
我完全同意:如果有一种方法可以validation您的模型,那么这是防止重复记录的最安全的方法。
你仍然可以做两件事。 防止浏览器缓存:当用户单击后退按钮时,表单中的字段将显示为空。 单击时禁用“创建”按钮。
= f.submit "Create", :disable_with => "Processing..."
当您的用户按下后退按钮时,该按钮将被禁用。
您可以使用validation器确保不插入重复值。 在这种情况下, validates_uniqueness_of :field
例如,如果您想阻止用户使用相同的电子邮件地址,则可以在用户模型中添加以下代码。
validates_uniqueness_of :email
这将检查列中是否存在与您尝试惰性的条目相同的任何先前条目。 祝好运
基于@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总是被重置,所以它无法在每次比较时进行比较需要
这对我有用。
您需要做两件事:在控制器中创建一个方法,并在“create”方法下的同一个控制器中添加一个条件语句。
1)您的方法应该返回该用户的该对象的总数。
EX:
def用户current_user.object.count结束
2)在’create’方法中添加条件语句。
例:
def create @object = Object.create(object_params)@ object.save if user == 0 redirect_to x_path end
我希望这有帮助!