rails prepend_view_path of mountable engine

孤者浪人 提交于 2020-01-13 03:56:12

问题


In one hand, I have a mountable engine let's say Front Front contain my assets and couple of pages It's isolated from MainApp. I don't want it to touch the main app.

In the other hand I want my MainApp using layout and partial of the Front. So I setup the layout this way :

class ApplicationController < ActionController::Base
    layout 'front/application'
end

But the front/application refer to engine partial directly, because of isolation, like this

render 'header' # front/ prefix is not required

So the MainApp views try to load app/views/application/header instead of app/views/front/application/header

To fixe this I put a prepend_view_path like this :

class ApplicationController < ActionController::Base
    layout 'front/application'
    before_filter :prepend_front
protected
    def prepend_front
       prepend_view_path "app/views/front"
    end
end

But this doesn't work because engine path point into the vendor. The engine add it self this to the prepend path list : ~/main_app/vendor/private_gems/front-0.0.2/app/views And my preprend_front method create this : ~/main_app/app/views/front

I tryed to prepend by force the correct path (but it looks so dirty) :

prepend_view_path "#{Rails.root}/vendor/private_gems/front-0.0.2/app/views/front"

I doesn't work, just crash the app ...

And I'm stuck here. Maybe my design is wrong?


回答1:


The answer from Jack is perfect except if you want to do this inside the Rails engine (for example if your engine itself has 'themes' that require a different load path). In this case the prepend_path and append_path are not appropriate since you are going to want to insert your new load path before the engines default load path but after the applications load path.

A solution to this (only tested in Rails 3.2) is to add the following to your engines /lib/my_engine.rb file:

config.after_initialize do
  my_engine_root = MyEngine::Engine.root.to_s
  paths = ActionController::Base.view_paths.collect{|p| p.to_s}
  paths = paths.insert(paths.index(my_engine_root + '/app/views'), my_engine_root + '/app/views/themes/my_theme')
  ActionController::Base.view_paths = paths
end

The new load path my_engine_root + '/app/views/themes/my_theme' will now be just before your engines standard load path my_engine_root + '/app/views'




回答2:


By default, Rails looks in views/ for the file, but when it doesn't find it, it'll look inside the engine's views/. This means you'll have to append the views path so that Rails will look in main app's views/ and then the modified path in your engine, and finally the engine's views/. This would then be the stack:

  • main app views/
  • engine modified path (views/front/ inside engine)
  • engine views/

To do this, go into application_controller.rb

class ApplicationController < ActionController::Base

    before_filter :set_views_path

    def set_views_path
        append_view_path FnetIdentityRailsEngine::Engine.root.join('app', 'views', 'front')
    end
end

If you prepended your views path with the modified path in the engine, you wouldn't get the ability to override engine views in the main app. This is why you'd want to append.




回答3:


Finally I remove the isolate property. I moved my views one folder up, so out of the engine_app folders.

The only final ajustement was to include EngineApp::Engine.url_helper into the MainApp application controller.

The prepend stack look like this :

  • Main App prepended path
  • Main App views
  • Engine views

So it's based on the engine, then add main app stuff on the top.



来源:https://stackoverflow.com/questions/9769337/rails-prepend-view-path-of-mountable-engine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!