2

我将 I18n 添加到使用 Devise 的 RoR 应用程序中,如果我尝试重置密码,现在会出现错误。错误是:

Routing Error
No route matches {:action=>"edit", :controller=>"devise/passwords", :reset_password_token=>"uMopWesaxczNn2cdePUQ"} 

如何正确设置我的设计路由以考虑 I18n?

路线.rb

 scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do   
  devise_for :users, path_names: {sign_in: "login", sign_out: "logout"},
                   controllers: {omniauth_callbacks: "omniauth_callbacks"}
  root to: 'static_pages#home'
 end

   match '*path', to: redirect {|params| "/#{I18n.default_locale}/#{CGI::unescape(params[:path])}" }, constraints: lambda { |req| !req.path.starts_with? "/#{I18n.default_locale}/" }
   match '', to: redirect("/#{I18n.default_locale}")

application_controller.rb

before_filter :set_locale
 def set_locale
   I18n.locale = params[:locale] if params[:locale].present?
 end

 def default_url_options(options = {})
   {locale: I18n.locale}
 end
4

3 回答 3

8

我确实为这种情况创建了一个示例应用程序(设计+国际化)。自从我创建该应用程序以来已经有一段时间了,它可能有点错误/不完整,但关键是使用带括号的可选范围。

devise_for :users当您没有设置变量时,您的代码问题没有定义:locale(这是我从您的错误中猜测的,您的路线中的重定向代码可能不起作用 - 您真的不需要,我没有测试,但我不认为这是一个很好的做法)。此外,这就是它试图将令牌值分配为:locale变量的原因。

相反,您需要使用括号。所以这:locale将是可选的,并且您的路由定义在:locale未设置时将保持有效。

scope "(:locale)", :locale => /en|tr/ do
  devise_for :users
  root :to => "main#index"
end

我希望它有所帮助。

于 2012-08-13T10:52:14.780 回答
2

我有同样的问题(密码重置时出现路由错误),但这是我找到的解决方案:路由错误不是由控制器或任何其他设计内部进程引起的,而是由视图引起的。views/devise/mailer/reset_password_instructions.html.erb在行中:

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %>

需要更换为:

<%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token, :locale => I18n.locale) %>`

我不知道为什么默认情况下不添加 locale 参数。

于 2014-04-07T18:36:57.167 回答
0

我对设置 Devise 了解不多,但我确实花了一些时间研究国际化 Rails 路由,所以希望这个答案对你有用,如果不是作为你问题的答案,那么作为一个接近答案的参考(内容主要是我在 i18n Railscast 的评论中写的评论的重新散列,这也是 Rails i18n 路由信息的良好来源):

您的application_controller.rb对我来说看起来不错,但也许尝试将您的routes.rb更改为如下所示:

config/routes.rb(示例)

MyApp::Application.routes.draw do
  scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do
    # ...
    match '/about',   to: 'static_pages#about'

    # handles /valid-locale
    root to: 'static_pages#home', as: "locale_root"
    # handles /valid-locale/fake-path
    match '*path', to: redirect { |params, request| "/#{params[:locale]}" }
  end

  # handles /
  root to: redirect("/#{I18n.default_locale}")
  # handles /bad-locale|anything/valid-path
  match '/*locale/*path', to: redirect("/#{I18n.default_locale}/%{path}")
  # handles /anything|valid-path-but-no-locale
  match '/*path', to: redirect("/#{I18n.default_locale}/%{path}")
end

由于有两个root_paths,我在:locale范围内重命名了一个,这样应用程序和测试就不会发生冲突。我使用 RSpec 测试了路由,如下所示:

规范/路由/routing_spec.rb

require 'spec_helper'

describe "Routes" do

  describe "locale scoped paths" do
    I18n.available_locales.each do |locale|

      describe "routing" do
        it "should route /:locale to the root path" do
          get("/#{locale.to_s}").
            should route_to("static_pages#home", locale: locale.to_s)
        end
      end

      describe "redirecting", type: :request do

        subject { response }

        context "fake paths" do
          let(:fake_path) { "fake_path" }

          before { get "/#{locale.to_s}/#{fake_path}" }
          it { should redirect_to(locale_root_path(locale)) }
        end
      end
    end
  end

  describe "non-locale scoped paths" do

    describe "redirecting", type: :request do

      subject { response }

      context "no path given" do
        before { get "/" }
        it { should redirect_to(locale_root_path(I18n.default_locale)) }
      end

      context "a valid action" do
        let(:action) { "about" }
        let!(:default_locale_action_path) { about_path(I18n.default_locale) }

        context "with a valid but unsupported locale" do
          let(:unsupported_locale) { "fr" }

          before { get "/#{unsupported_locale}/#{action}" }
          it { should redirect_to(default_locale_action_path) }
        end

        context "with invalid information for the locale" do
          let(:invalid_locale) { "invalid" }

          before { get "/#{invalid_locale}/#{action}" }
          it { should redirect_to(default_locale_action_path) }
        end

        context "with no locale information" do
          before { get "/#{action}" }
          it { should redirect_to(default_locale_action_path) }
        end
      end

      context "invalid information" do
        let(:invalid_info) { "invalid" }

        before { get "/#{invalid_info}" }
        it { should redirect_to("/#{I18n.default_locale}/#{invalid_info}") }
        # This will then get caught by the "redirecting fake paths" condition
        # and hence be redirected to locale_root_path with I18n.default_locale
      end
    end
  end
end
于 2012-08-12T15:25:35.517 回答