Rails MVC如何将随机生成的数组传递到下一页并保持元素不变
问题原因
Rails基于无状态HTTP协议实现,每次用户发起请求(访问游戏页是第一次请求、提交表单跳结果页是第二次独立请求),都会新建一个完全独立的控制器实例。两次请求的实例数据不互通,initialize方法会在每次实例化时重新执行,写在其中的随机字母采样逻辑会跑两次,自然结果页拿到的是全新的随机字母组,和游戏页展示的不一致。
实例变量的生命周期仅绑定当前控制器实例,请求结束实例销毁后,对应的实例变量也会被回收,根本无法跨请求传递。
可行解决方案
方案1:Session存储(优先选择,天然防篡改)
Session是Rails内置的用户级会话存储机制,同一名用户的多次请求可以共享Session内的数据,数据存在服务端,用户无法私自篡改:
- 在
game动作中生成字母组后存入Session
def game @letters = ('a'..'z').to_a.sample(10) session[:current_game_letters] = @letters end
- 在
results动作中从Session取出字母组使用
def results @letters = session[:current_game_letters] # 直接用@letters做单词拼写合法性校验,也可传给视图渲染 # 本局结束后删除Session里的旧数据,避免影响下一局游戏 session.delete(:current_game_letters) end
视图中直接通过<%= @letters %>即可渲染和游戏页完全一致的字母组。
方案2:表单隐藏字段传参(适合无防作弊需求的轻量场景)
把生成的字母组作为隐藏参数嵌入游戏页的提交表单,用户提交答案时会自动将该参数带到结果页:
- 在游戏页的表单内添加隐藏输入项
<%= form_tag results_path do %> <!-- 原有表单项:单词输入框、提交按钮等 --> <%= hidden_field_tag :game_letters, @letters.join(',') %> <%= submit_tag "提交答案" %> <% end %>
- 在
results动作中接收参数并还原为字母数组
def results @letters = params[:game_letters].split(',') # 后续校验、渲染逻辑 end
注意:该方案的参数由前端传递,用户可通过浏览器开发者工具随意修改字母组内容,如果游戏涉及计分、排行等公平性要求高的逻辑,禁止使用该方案。
避坑提醒
不要用类变量(@@letters)、全局变量($letters)存储字母组,这类变量是所有用户共享的,多用户同时访问时会出现字母组互相串数据的问题,完全无法正常使用。
内容的提问来源于stack exchange,提问作者Nostalgia
相关产品推荐
相关产品推荐

