devise_invitable - Rails url 在 DeviseInvitable 控制器的应用程序布局中找不到助手

devise_invitable - Rails url helpers not found in application layout in DeviseInvitable controller

我正在写一个 Rails 引擎(订阅),它将成为多租户 Rails 应用程序的基础,并处理子域、帐户、用户(使用 Devise)和订阅。

除了 devise_invitable Devise::InvitationsController 呈现应用程序布局时,一切正常。发生这种情况时,布局渲染会崩溃并出现以下错误: 未定义局部变量或方法`destroy_user_session_path'

我不知道为什么 url 助手在此上下文中不可用,因为它们似乎可用于应用程序的其余部分。

应用程序布局仍然可以访问 current_user 等 Devise 变量,如果我删除 link 到 destroy_user_session_path 邀请#新动作使布局很好。

虚拟应用程序 (spec/dummy) 中的

运行 "rake routes" 正确显示路线。我还尝试了以下方法:

config/routes.rb

require 'subscribe/constraints/subdomain_required'
require 'subscribe/constraints/no_subdomain'

Subscribe::Engine.routes.draw do

  constraints Subscribe::Constraints::SubdomainRequired do
    scope module: "account" do
      root to: "dashboard#index", as: :account_root
    end

  devise_for :users, 
    class_name: "Subscribe::User", 
    module: :devise, 
    path: "/",
    :controllers => { :invitations => 'subscribe/user_invitations' }

  resources :users

end

spec/dummy: 'rake routes'

Routes for Subscribe::Engine:
          account_root GET    /                            subscribe/account/dashboard#index
      new_user_session GET    /sign_in(.:format)           devise/sessions#new
          user_session POST   /sign_in(.:format)           devise/sessions#create
  destroy_user_session DELETE /sign_out(.:format)          devise/sessions#destroy
         user_password POST   /password(.:format)          devise/passwords#create
     new_user_password GET    /password/new(.:format)      devise/passwords#new
    edit_user_password GET    /password/edit(.:format)     devise/passwords#edit
                       PATCH  /password(.:format)          devise/passwords#update
                       PUT    /password(.:format)          devise/passwords#update
accept_user_invitation GET    /invitation/accept(.:format) subscribe/user_invitations#edit
remove_user_invitation GET    /invitation/remove(.:format) subscribe/user_invitations#destroy
       user_invitation POST   /invitation(.:format)        subscribe/user_invitations#create
   new_user_invitation GET    /invitation/new(.:format)    subscribe/user_invitations#new
                       PATCH  /invitation(.:format)        subscribe/user_invitations#update
                       PUT    /invitation(.:format)        subscribe/user_invitations#update
                 users GET    /users(.:format)             subscribe/users#index
                       POST   /users(.:format)             subscribe/users#create
              new_user GET    /users/new(.:format)         subscribe/users#new
             edit_user GET    /users/:id/edit(.:format)    subscribe/users#edit
                  user GET    /users/:id(.:format)         subscribe/users#show
                       PATCH  /users/:id(.:format)         subscribe/users#update
                       PUT    /users/:id(.:format)         subscribe/users#update
                       DELETE /users/:id(.:format)         subscribe/users#destroy

config/initializers/devise.rb

config.parent_controller = 'Subscribe::ApplicationController'
config.router_name = :subscribe
config.scoped_views = true

spec/dummy/app/views/layouts/application.html.slim

doctype html
html
  head
    title
    = javascript_include_tag "application", "data-turbolinks-track" => true
    = csrf_meta_tags
  body
    - flash.each do |k,v|
      div class = "flash #{k}"
        = v
    br

    - binding.pry
    - if user_signed_in?
      = "Signed in as #{current_user.email}"
      = link_to "Sign out", destroy_user_session_path, method: :delete 
    -  else
      = "Not signed in"
    br

    == yield

app/controllers/subscribe/user_invitations_controller.rb

module Subscribe
  class UserInvitationsController < Devise::InvitationsController
    include Rails.application.routes.url_helpers
    include Rails.application.routes.mounted_helpers

    def new
        #binding.pry
        super
    end

  end
end

subscribe.gemspec

$:.push File.expand_path("../lib", __FILE__)

# Maintain your gem's version:
require "subscribe/version"

# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
  s.name        = "subscribe"
  s.version     = Subscribe::VERSION
  s.authors     = ["author"]
  s.email       = ["author@example.com"]
  s.homepage    = "https://.com"
  s.summary     = "Subscriber engine for .com"
  s.description = "..."

  s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]

  #Framework
  s.add_dependency "rails", "~> 4.1.0"

  #Auth
  s.add_dependency "devise", "~>3.5.0"
  s.add_dependency "devise_invitable", "~>1.5.5"
  s.add_dependency "pundit", "~>0.2.3"

  #Layout and interface
  s.add_dependency "slim-rails", "~> 2.1.2"
  s.add_dependency "jquery-rails", "~> 3.1.4"

  #Testing
  s.add_development_dependency "rspec-rails", "~> 3.0.0"
  s.add_development_dependency "capybara", "~> 2.3.0"
  s.add_development_dependency "capybara-screenshot", "~> 0.3.17"
  s.add_development_dependency "factory_girl_rails", "~> 4.4.1"
  s.add_development_dependency "database_cleaner", "~> 1.2.0"

  #Tools and support
  s.add_development_dependency "spring", "~> 1.1.3"
  s.add_development_dependency "spring-commands-rspec"
  s.add_development_dependency "sqlite3"

  s.add_development_dependency "better_errors"
  s.add_development_dependency "binding_of_caller"
  s.add_development_dependency "pry-rails"
  #s.add_development_dependency "guard-rspec" - does not work atm
  s.add_development_dependency "rb-inotify"
  s.add_development_dependency "libnotify"

end

app/controllers/subscribe/application_controller.rb

module Subscribe
  class ApplicationController < ActionController::Base
    layout "application"
    protect_from_forgery with: :exception    
  end
end

可在此处找到当前正在进行的工作的完整源代码(README.md 已过时):

https://github.com/heliohm/Subscribe

在 Devise 控制器的上下文中,路径似乎必须是带有引擎名称的名称spaced。

destroy_user_session_path 更改为 subscribe.destroy_user_session_path 即可解决问题。

由于引擎是 namespaced,因此还需要覆盖 devise_invitable 中包含的默认视图(例如 app/views/devise/mailer/invitation_instructions.html.erb),因为它们使用root_url 等路由在这种情况下不存在。

这也是所有 Devise 控制器的情况,例如Devise SessionsController 也不会在顶级名称 space.

中找到这些路由