在应用程序布局中渲染引擎

Jør*_*n R 30 ruby-on-rails-plugins rails-engines ruby-on-rails-3

背景

我正在创建一个由核心和几个模块组成的应用程序.这些模块是rails引擎,并提供实际功能,因为核心本身仅充当主机.引擎托管/lib在各自的路径上并安装在它们各自的路径上.

coreApp
???lib
   ??? module1
   ??? module2
   ??? etc
Run Code Online (Sandbox Code Playgroud)

然后像这样安装模块

mount Module1::Engine => "/module1", :as => "module1"
mount Module2::Engine => "/module2", :as => "module2"
Run Code Online (Sandbox Code Playgroud)

虽然登录本身是由模块完成的,但核心也负责处理会话.

问题

我还没有找到一种与引擎共享核心应用程序布局的好方法.截至目前,这就是我如何使布局可用于引擎:

coreApp
??? app
    ??? views
        ??? layouts
            ??? application.html.erb
            ??? core.html.erb
Run Code Online (Sandbox Code Playgroud)

该文件core.html.erb仅包含

<%= render :template => 'layouts/application' %>
Run Code Online (Sandbox Code Playgroud)

然后是这样包含在每个模块中

module Module1
  class ApplicationController < ActionController::Base
    layout "core"
  end
end
Run Code Online (Sandbox Code Playgroud)

虽然它不是特别优雅,但它工作正常,并且模块的内容呈现在yield应用程序布局中的语句所在的位置.

问题如下:

1.标题中不包含模块特定的样式表

我需要一种方法来包含活动模块的样式表.

2.标头需要访问有关登录用户的信息

标题包含有关登录用户的信息,例如

Logged in as <%= @user[:realname] %>
Run Code Online (Sandbox Code Playgroud)

这来自核心 home_controller

def index
  @user = User.find_by_id(session[:user])
end
Run Code Online (Sandbox Code Playgroud)

但是当我尝试访问该模块时,我收到以下错误

NoMethodError in Module1/home#index

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
Run Code Online (Sandbox Code Playgroud)

显然是指@user.

如何在没有太多篡改发动机的情况下尽可能优雅地和干燥地解决这个问题?

我已经用Google搜索了很多但是无法真正理解如何解决它.可能完全缺乏对rails如何工作的洞察力,因此这个问题很有可能对于那些了解rails的人来说甚至都没有意义.

如果有任何不清楚或含糊不清的地方请评论,我会尽力详细说明.

The*_*dis 41

我已成功在我的引擎中使用了我的父应用程序的布局.首先,根据Rails指南(引擎)的第4.3.2节,为了访问父应用程序ApplicationController的变量(比如session,如上所述),您需要替换application_controller.rb当前拥有的引擎:

module Module1
  class ApplicationController < ActionController::Base
    layout "core"
  end
end
Run Code Online (Sandbox Code Playgroud)

对此:

class Module1::ApplicationController < ::ApplicationController
end
Run Code Online (Sandbox Code Playgroud)

这将继承父应用程序的ApplicationController及其所有变量.

其次,您需要app/views/layouts/application.html.erb从引擎视图中删除该文件,因为您使用的是父应用程序,因此不需要它.

现在,当您从父应用程序渲染Module1的视图时,将使用父应用程序的布局,并且session[]将正确评估所有变量.

别忘了添加"main_app"字样.在布局中的每个链接之前,否则它将尝试查找引擎中的路径而不是父应用程序.例如,如果父应用程序中的布局包含指向some_path(即父应用程序中的视图)的链接,则在使用此布局的引擎中显示视图时,将尝试some_path在Engine中查找而不是在父应用程序中查找.您需要更改链接才能main_app.some_path使其正常工作.

希望这可以帮助.

  • 我认为这是正确的.这不是我想要的,但足够接近,无论如何项目都已完成.感谢您抽出宝贵的时间. (2认同)

mon*_*ike 17

使用 layout 'layouts/application'

如果您不想使用main_app.your_path,您还可以添加:

module YourEngine
  module ApplicationHelper
    def method_missing(method, *args, &block)
      if (method.to_s.end_with?('_path') || method.to_s.end_with?('_url')) && main_app.respond_to?(method)
        main_app.send(method, *args)
      else
        super
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


Sha*_*ler 7

我的申请也做了同样的事情.我所做的只是:

  1. 删除/ app/view/layouts /中的引擎布局
  2. 将application_controller更改为

    module EngineModule
      class ApplicationController < ::ApplicationController
        layout 'layouts/application' 
      end
    end
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在您的视图中,如果您想引用任何路径,例如login_path,可以通过它来引用main_app.login_path