用于 ajax 目的从模型级别到控制器级别的消息传递
我有一个名为 /examples/1/duplicate 的页面 有一个 ajax 表单,它启动 /examples/1/run_duplicate
run_duplicate 的控制器方法运行 Example.duplicate(session) 我通过了会议,我知道这是一个神圣的禁忌。
重复的模型代码大致如下:
def duplicate(session)
session[:duplicate] = 0
duplicate_foobars
session[:duplicate] = 1
duplicate_snafus
session[:duplicate] = 2
duplicate_widgets
session[:duplicate] = 3
end
我在重复的页面上有另一个控制器方法,该方法正在进行长轮询:/examples/1/check_dupe_status 目的是从会话[:duplicate]获取更新的状态,调整进度报告, 并通过 ajax 将其报告给用户,以便他们可以看到 Example.duplicate() 的进度。
会话没有按照我希望的方式更新。我可以看到代码运行,但会话不会更新,因此 /examples/1/check_dupe_status 永远不知道任何事情已经开始。
鉴于我从一开始就做错了,通知用户 Example.duplicate() 状态的正确方法是什么?
I have a page called /examples/1/duplicate
on there is an ajax form which kicks off /examples/1/run_duplicate
the controller method for run_duplicate runs Example.duplicate(session)
I pass in the session, which I understand is a holy no-no.
the duplicate model code is roughly:
def duplicate(session)
session[:duplicate] = 0
duplicate_foobars
session[:duplicate] = 1
duplicate_snafus
session[:duplicate] = 2
duplicate_widgets
session[:duplicate] = 3
end
I have another controller method on the duplicate page which is doing a long poll: /examples/1/check_dupe_status
The purpose was to get the updated status from session[:duplicate], tweak a progress report,
and report it back to the user via ajax so they could see the progress of Example.duplicate() .
sessions did not update the way I hoped. I can see the code run, but the sessions don't update, so /examples/1/check_dupe_status never knows that anything has kicked off.
Given that I did this wrong from the start, what is the correct way to notify a user about the state of Example.duplicate() ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来您有两个单独的请求,一个请求写入会话,一个尝试同时从会话中读取。这是正确的吗?如果不是,请停止阅读。
这是行不通的,因为“会话”只是一个 cookie - HTTP 响应上的一个标头,它作为 cookie 下载到您的浏览器,然后在下一个请求时重新上传,然后在下一个响应时重新下载,ad nosium。在您的代码中,操作顺序如下:
/examples/1/run_duplicate 将“0”写入本质上是 Ruby 哈希的内容,代表您的会话 cookie
/examples/1/check_dupe_status 读取刚刚从您的浏览器发送的会话 cookie 中的值这个请求。 :duplicate 中可能根本没有任何内容,因此它将显示为空白。
/examples/1/run_duplicate 将“1”写入 Ruby 会话哈希
/examples/1/check_dupe_status 再次读取,该请求发送的会话 cookie - 没有任何变化
/examples/1/run_duplicate 将“2”写入 Ruby 会话哈希
/examples/1/check_dupe_status 从会话读取它最初发送的 cookie - 没有变化
/examples/1/run_duplicate 将“3”写入 Ruby 会话哈希并且请求完成,将会话作为值 3 的 cookie 发送回 :duplicate。
/examples/1/check_dupe_status 仍然像 dufus 一样坐在那里,读取它最初发送的空白会话 cookie
在某些时候,/examples/1/check_dupe_status 可能会超时,并且它可能会与会话 cookie 一起返回。但你猜怎么着?由于 :duplicate 从未在该会话 cookie 中设置,因此它将覆盖浏览器中的 cookie,并且 :duplicate 在您发送的下一个请求中将为空。
希望我清楚地表达了这一点。基本上,您在 cookie 中遇到了竞争条件,如果您从同一浏览器发送并发请求,则很难克服这一点。
处理此问题的最佳方法是将重复的 0、1、2 等值写入某个数据库表。然后,您的长轮询请求就可以从数据库中读取。也许效率有点低,但当然它有一个优点,那就是它可以工作。
Sounds like you've got two separate requests, with one writing to the session and one trying to read from the session concurrently. Is that correct? Stop reading if it's not.
This can not work because the "session" is just a cookie - a header on the HTTP response that's downloaded to your browser as a cookie, then re-uploaded on the next request, then re-downloaded on the next response, ad nosium. In your code, here is the order of operations:
/examples/1/run_duplicate writes "0" to what is essentially a Ruby Hash, representing your session cookie
/examples/1/check_dupe_status reads the values from the session cookie that was just sent from your browser with this request. It probably didn't have anything at all in :duplicate, so it will appear as blank.
/examples/1/run_duplicate writes "1" to the Ruby session Hash
/examples/1/check_dupe_status reads, again, the session cookie which that request sent - nothing has changed
/examples/1/run_duplicate writes "2" to the Ruby session Hash
/examples/1/check_dupe_status reads from the session cookie it originally sent - no change
/examples/1/run_duplicate writes "3" to the Ruby session Hash and the request finishes, sending the session back as a cookie with a value of 3 at :duplicate.
/examples/1/check_dupe_status is still sitting there like a dufus, reading the blank session cookie it originally sent
At some point, /examples/1/check_dupe_status may timeout, and it may return with the session cookie. But guess what? Since :duplicate was never set in that session cookie, it will overwrite the one in your browser, and :duplicate will be blank in the next request you send.
Hopefully I expressed that clearly. Basically you're hitting a race condition in your cookies, and that's very difficult to overcome if you're sending concurrent requests from the same browser.
The best way to handle this would be to write your duplicate 0,1,2, etc. values to some database table. Your long-polling request could then just read out of the database. A little less efficient perhaps, but of course it has the advantage that it could work.