【问题标题】:Rails controller actions & cache - handling simultaneous/overlapping requestsRails 控制器动作和缓存 - 处理同时/重叠的请求
【发布时间】:2016-09-13 19:35:14
【问题描述】:

我的 Rails 应用程序依赖 Rails 缓存来临时保存用户输入并在用户登录过程中在控制器操作之间传递它。但是,我意识到我犯了一个非常严重的错误(因为我通常是 Rails 和 MVC 的超级新手)并且可以使用一些帮助/建议/智慧 - 基本上,如果两个用户同时(或几乎同时)提交数据并通过下面的控制器步骤,会有一些麻烦 - 丢失数据,一个用户的数据被输入为另一个,等等。当我构建这个时,我不了解控制器的性质,虽然我肯定有现在更好的主意....

简而言之,以下代码的工作方式如下:未登录用户填写表单并提交数据,该数据被传递给submission 操作并保存在名为@987654323 的Rails 缓存对象中@;然后提示用户登录(通过 Devise),成功登录会触发 approval 控制器操作,该操作读取 incoming_report 缓存对象,将该数据保存到数据库,然后创建一个名为 @ 的新缓存对象987654326@ 挂在用户条目的 id # 上;这将重定向到 summary 操作,该操作收集这些 id 并将相应的数据显示给用户作为其条目的摘要。

report_controller.rb

#ON SUBMITTING THE FORM...
def submission
    @incomingReport = ActiveSupport::JSON.decode(params[:report])

    #SUBMITTED DATA IS HELD IN THE CACHE AS 'incoming_report' TO PASS TO approval CONTROLLER ACTION ON SUCCESSFUL LOGIN
    Rails.cache.write("incoming_report",@incomingReport)
end

#ON SUCCESSFUL LOG IN...
def approval
    @incomingReport = Rails.cache.read("incoming_report")
    @newReportIDArray = Array.new

    @incomingReport.each do |x|
        #DATA PROCESSING STUFF HERE...
    end

    #DELETE 'incoming_report' FROM CACHE
    Rails.cache.delete("incoming_report")

    #ID NUMBERS OF ENTRIES ARE HELD TO PASS TO summary CONTROLLER ACTION
    Rails.cache.write("ids",@newReportIDArray)

    redirect_to report_summary_path
end

#AFTER DATA IS ENTERED...
def summary
    @newReportIDs = Rails.cache.read("ids")
    #DELETE 'ids' FROM CACHE
    Rails.cache.delete("ids")
end

在大多数情况下,这很有效,但如果用户在任何这些操作中相互交叉,那将是灾难性的。例如,如果一个用户在另一个用户忙于登录时点击了submission 操作,则第二个用户的incoming_report 对象将覆盖第一个用户的对象......等等。

这个问题的主要来源是用户在单击表单提交按钮后登录 - 应用程序必须以这种方式构建 - 并且数据不能保存在本地/会话存储对象中,因为它包含base64 字符串,并且太长而无法在某些浏览器中使用这些方法。在我注意到这个问题之前,将这些数据保存在服务器上似乎是最好的做法......

有什么方法可以防止用户在控制器中互相干扰?还是我犯了一个非常致命的错误?

编辑以显示解决方案

最终,使用会话变量而不是 Rails 缓存节省了一天的时间。这是重新配置的控制器以显示解决方案...

def submission
    @incomingReport = ActiveSupport::JSON.decode(params[:report])

    @newReportIDArray = Array.new

    @incomingReport.each do |x|
        #DATA PROCESSING STUFF HERE
        @newReportIDArray.push(@new_report.id)
    end

    session[:ids] = @newReportIDArray

    respond_to do |format|
      format.json do
        render json: {
          success: 200
        }.to_json
      end
    end
end

def approval
    @reportIDs = session[:ids]

    @reportIDs.each do |x|
        @new_report = Report.find(x)
        @new_report.user_id = current_user.id
        @new_report.save
    end

    redirect_to report_summary_path
end


def summary
    @reportIDs = session[:ids]
end

非常感谢在这方面帮助我并向我展示会话变量的方式的两个人。

我遇到了会话变量在控制器操作之间“丢失”的问题 - Rails / Devise - updating session variables between controller actions

【问题讨论】:

  • 您应该使用特定于浏览器的会话而不是缓存。
  • @JohnNaegle 谢谢!你和 Wade73 给了我很好的思考。
  • @JohnNaegle 太棒了,谢谢你的建议。我不得不稍微修改一下逻辑,但使用会话变量完全解决了我的问题。

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

我建议您将初始信息存储到数据库中。从那里我要么将 id 保存在 cookie 或会话变量中。然后,您将能够从审批控制器中的数据库中检索信息。我会考虑的另一个选择是生成一个 guid 作为 id 并将其作为查询字符串参数传递给登录页面。将 guid 存储在表单标签下的隐藏输入标签中。然后当用户提交他们的凭据时,您也可以传递 guid。此时您将它们登录。如果成功,从发布的数据中提取 guid,然后使用 guid 检索数据库信息。

韦德

【讨论】:

  • 这很有趣,当我发布此消息后走在街上时,我心想'为什么不记录提交时的数据,然后在成功/不成功登录时保留或删除它?'。我必须考虑一下,但我相信你已经让我走上了正确的道路——如果我能让它发挥作用,我肯定会接受你的回答。
  • 是的!我不得不重新配置控制器和逻辑,但只需保存为会话变量即可。非常感谢你的帮助!编辑我的问题以显示解决方案...
  • 没问题,尽情享受吧!
  • 其实我是误会了问题,想出了一个更好的方法问-stackoverflow.com/questions/39501992/…
  • 老实说,我是 Ruby on Rails 的新手,尽管我在 ASP.Net 上做了几年的 Web 开发人员。不确定我是否会提供超出我提供的帮助。
猜你喜欢
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
  • 2013-06-19
  • 2014-12-08
  • 2016-01-27
相关资源
最近更新 更多