Ruby on Rails视图不改变当前路由如何调用控制器方法
Rails 无路由跳转切换I18n语言方案
你在application_controller.rb中定义的switch_locale是控制器请求级别的回调钩子,无法直接被视图层的按钮/链接主动触发,要实现不改变当前页面路由、不跨页跳转的语言切换,可直接用以下两种方案:
方案1:当前页参数重载(最符合Rails约定,推荐测试阶段使用)
这个方案不会跳转到其他路由,只会在当前访问路径上追加locale参数后重载页面,路由路径和你当前访问的地址完全一致,实现成本极低。
- 首先微调控制器的locale读取逻辑,兼容临时传参方便测试:
# application_controller.rb around_action :switch_locale def switch_locale(&action) # 优先级:url临时参数 > 登录用户保存的偏好 > 系统默认语言 locale = params[:locale] || current_user.try(:locale) || I18n.default_locale I18n.with_locale(locale, &action) end # 配置默认url参数,保证全站链接自动带上当前locale def default_url_options { locale: I18n.locale } end - 在全局布局文件中添加语言切换链接即可:
Rails生成上述链接时会自动复用当前页的路由参数,点击后只会重载当前页面,不会跳转到其他地址。如果需要永久保存用户的语言偏好,只要在切换时把传入的locale值更新到<!-- 语言切换栏,放在layouts/application.html.erb中全站生效 --> <div class="locale-switch"> <%= link_to "简体中文", { locale: :zh }, class: "locale-btn" %> <%= link_to "English", { locale: :en }, class: "locale-btn" %> </div>current_user的对应字段,后续访问就会自动读取用户设置。
方案2:AJAX异步切换(可实现完全无刷新)
如果需要完全不触发整页重载,可以通过异步请求提交语言设置:
- 先添加设置语言的路由:
# config/routes.rb post "/switch_locale", to: "application#set_locale", as: :switch_locale - 控制器中添加对应的设置逻辑,兼容登录用户和未登录访客:
# application_controller.rb def set_locale # 先做语言白名单校验,防止非法参数 if params[:locale].in?(%w[zh en]) # 替换成你项目实际支持的语言代码 current_user&.update(locale: params[:locale]) session[:locale] = params[:locale] # 未登录用户存在session里 end render json: { status: "ok" } end # 调整原有的locale读取逻辑,兼容session存储的设置 def switch_locale(&action) locale = params[:locale] || current_user.try(:locale) || session[:locale] || I18n.default_locale I18n.with_locale(locale, &action) end - 视图中添加切换按钮,绑定异步提交逻辑:
<button class="locale-ajax-btn" data-locale="zh">简体中文</button> <button class="locale-ajax-btn" data-locale="en">English</button> <script> document.querySelectorAll('.locale-ajax-btn').forEach(btn => { btn.addEventListener('click', async () => { const csrfToken = document.querySelector('meta[name="csrf-token"]').content await fetch('<%= switch_locale_path %>', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, body: JSON.stringify({ locale: btn.dataset.locale }) }) // 测试阶段直接重载当前页即可,要做完全无刷新可以在这里替换页面内的文案 window.location.reload() }) }) </script>
提示:纯无刷新替换文案需要给页面所有文本做前端标记,开发成本较高,功能测试阶段用方案1完全够用,符合Rails框架的设计约定,也不会出现路由跳转的问题。
内容的提问来源于stack exchange,提问作者grant
相关产品推荐
相关产品推荐

