Rails控制器动作&缓存 - 处理同时/重叠请求

时间:2016-09-13 19:35:15

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

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

简而言之,以下代码的工作方式如下:未登录的用户填写表单并提交传递给submission操作并保存在Rails缓存对象中的数据incoming_report;然后提示用户登录(通过Devise),并且成功登录会触发approval控制器操作,该操作将读取incoming_report缓存对象,将该数据保存到数据库,然后创建新的缓存对象ids以挂起用户条目的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

1 个答案:

答案 0 :(得分:1)

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

韦德