【问题标题】:dynamically intercept and recall Ruby on Rails Routes in Rails Engine在 Rails 引擎中动态拦截和调用 Ruby on Rails 路由
【发布时间】:2021-03-25 14:59:11
【问题描述】:

我目前正在开发一个 Rails 引擎,它将在一定范围内复制宿主应用程序的路由。因此,如果原始应用程序中存在路由get '/posts', to: 'posts#index', as: 'posts',则该路由也应在引擎安装get '/mount/posts' 下可用,但应指向主机应用程序中的相同Contoller#Action。 但是,我无法访问最终的应用程序,因此必须动态生成路由。

以下是我目前的方法,但也许以另一种方式效果更好?

# lib/embed_me.rb
require "embed_me/engine"
module EmbedMe
  # defines a scoped route under which the embedded content can be found
  mattr_accessor :scope_name, default: :embed
end


# lib/embed_me/engine.rb
module EmbedMe
  class Engine < ::Rails::Engine
    isolate_namespace EmbedMe

    initializer "embed_me", before: :load_config_initializers do |app|
      Rails.application.routes.append do
        mount EmbedMe::Engine, at: EmbedMe.scope_name
      end
    end
  end
end


# config/routes.rb
EmbedMe::Engine.routes.draw do
  match '/*path', to: 'application#index', via: :all
end


# app/controllers/embed_me/application_controller.rb
module EmbedMe
  class ApplicationController < ActionController::Base
    protect_from_forgery with: :exception

    def index
      # will validate existance of route, or raise ActionController::RoutingError
      path = Rails.application.routes.recognize_path(params[:path])
      controller = path[:controller]
      action = path[:action]

      # how to call original action?
    end
  end
end

我不能使用redirect_to("/#{params[:path]}"),因为它会将 URL 更改为无范围的 URL。 我不能使用render(action: action, controller: controller),因为只会渲染相应的视图,但是会跳过控制器中的逻辑。 (或者我做错了什么?) 我不能使用main_app.resource_path,因为路由不是静态的,并且因应用程序而异。

我也看过 Link 和 Link,但也无法真正发挥作用

【问题讨论】:

  • 这不是一条可行的前进道路。 Rails 不是为了从一个控制器到另一个控制器的内部“转发”而构建的,它会使调试变成真正的地狱。我猜你可能会做的是让你的引擎像 rails 一样读取路由文件并创建一个修改后的路由集合,然后以某种方式将其插入到主机应用程序中。这可能需要大量的工作和深入研究内部结构。我建议您先阅读medium.com/rubyinside/…。
  • 谢谢。我去看看链接

标签: ruby-on-rails ruby rails-routing rails-engines


【解决方案1】:

所以我让它或多或少地工作了。我没有找到解决这个确切问题的方法,所以我做了一些小的权衡。也就是说,我决定主机应用程序的管理员必须对路由进行一些小的更改。 基本上,我现在使用如下示例中的范围。

scope path: "/#{EmbedMe.scope_name}", as: EmbedMe.scope_name, is_embedded: true

为了让引擎的用户尽可能轻松,我集成了一个自定义路由函数,它处理路由的范围。

# lib/embed_me/rails/routes.rb
module ActionDispatch::Routing
  class Mapper
    def embeddable
      # note that I call the yield function twice, see describtion below
      yield
      scope path: "/#{EmbedMe.scope_name}", as: EmbedMe.scope_name, is_embedded: true do
        yield
      end
    end
  end
end


# [Host Application]/config/routes.rb
Rails.application.routes.draw do
  # not embeddable
  get '/private', to: 'application#private'

  # is embeddable
  embeddable do
    get '/embeddable', to: 'application#embeddable'
  end
end


# output of $rails routes
...
private           GET   /private(.:format)            application#private
embeddable        GET   /embeddable(.:format)         application#embeddable
embed_embeddable  GET   /embed/embeddable(.:format)   application#embeddable {:is_embedded=>true}
...

请注意,我调用了两次 yield 函数,一次是正常获取路由,一次是在作用域下。这样,我还可以为普通链接和嵌入式链接获得多个路径帮助器。

创建自定义路由方法的处理方式与 Devise 类似。 See Source

【讨论】:

    猜你喜欢
    • 2014-11-08
    • 1970-01-01
    • 2013-10-09
    • 2011-05-11
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 2011-04-17
    • 1970-01-01
    相关资源
    最近更新 更多