I recently came across a tricky situation related to rails view helpers.
The situation is like follows-
I am having a controller as Feature1::Feature1.1::Feature1.1.1Controller.
The Feature1.1 also includes other controllers like Feature1.1.2Controller, Feature1.1.3Controller...
So ofcourse related view helpers in folder app/helpers/feature1/feature1.1/...
Now the real problem I am facing is that a few helpers for feature1.1 includes the same method name method1 with related definition.
I was wondering how rails identifies all these helpers as I am noticing that the method1 i.e. being called in a view for the controller feature1.1.1 is using the definition of the method1 i.e. written for the controller feature1.1.2.
So does rails consider all helper modules defined in one folder as one?
In a view feature1/feature1.1/feature1.1.1/index I am making a method call for method1.
I am using rails3
It depends a little bit on your Rails version. With eralier Rails versions, Rails did only include application_helper.rb and <controler_name>_helper.rb.
Additional helper modules can be included via helper :helper_name1, :helper_name2, ... within your controller.
With later Rails verions (4.2.? and up, maybe previous versions too), Rails includes all helpers within your helper folder at once. You can set config.action_controller.include_all_helpers = false within application.rb and you will fall back to the old behaviour.
This makes the helper only available within your views. If you want to use a helper within your controller you still have to include your helper with include XXXHelper.
I did some research and would like to share some additional info.
As per #slowjack2k mentioned, view helpers are included by rails as a default behavior.
But my question was about the situation of same method names across multiple helpers.
I found this article to be useful in this scenario. Though it explains the behavior for Rails 4 but I found it behaves in the same fashion for Rails 3.2.2.
I will summarize the article -
If there will be any conflict in the same names of methods in different helper modules, rails will use method from latter file (alphabetically)
Related
I was hired some days ago to update a Rails 4 app. In general the rspecs and the code look good however in the top of some controller a found this line:
delegate :edit_app_path, :new_app_payment_path, to: :view_context
Searching in the net, I found that the line is a way to load methods from the helpers inside a controller through a new instance of ActionView::Base class. I mean, is a way to do it instead of the classic:
include MyHelper
in the controller. My question is: is this really a good practice? is faster? AFAIK, view_context will load a new class with all the helpers and all the context of the view instead of one helper if I use the classic "include MyHelper". By the way :edit_app_path and :new_app_payment_path methods are in the same helper.
Should I remove the line?
Using view_context allows the controller to be blissfully ignorant of where the path is defined. If the helper file structure is refactored in future, the controller will continue humming along without requiring change.
Performance wise, I doubt the impact will be significant since all the code will have been loaded. Rails (and the Ruby standard library) creates new objects all the time.
I'm writing a configurable Rails engine. I have an authentication_helper configuration option to define which helper should be called in a before_action in all controllers needing authentication.
The problem is that I don't have access to the parent app's helpers from the engine's controllers. My understanding is that this happens because the engine is isolated.
I have considered using a block instead of a method name, but I'm not sure if that would work, or if I would be able to cleanly access the authorization logic from outside my controllers.
Active Admin, which I have used in the past, has a similar configuration option. I have noticed that their engine is not isolated, so perhaps I'm overrating the importance of engine isolation?
Is there an elegant way to have the benefits of engine isolation while also allowing this kind of customization? Or should I just forego isolation altogether?
EDIT #1
Brad Werth pointed my in the right direction, as this works with a regular controller inheriting from ApplicationController::Base:
module MyBigFancyEngine
class Engine < Rails::Engine
isolate_namespace MyBigFancyEngine
config.to_prepare do
# Make the implementing application's helpers available to the engine.
# This is required for the overriding of engine views and helpers to work correctly.
MyBigFancyEngine::ApplicationController.helper Rails.application.helpers
end
end
end
However, my engine's ApplicationController inherits from RocketPant::Base, which does not provide a helper method. I've tried to use a simple include (which works fine for regular controllers), but that doesn't work either (the controller can't find the helper).
Any ideas?
You can expose the implementing application's helpers available to the engine by including the following code in your engine.rb file:
engine.rb
module MyBigFancyEngine
class Engine < Rails::Engine
isolate_namespace MyBigFancyEngine
config.to_prepare do
# Make the implementing application's helpers available to the engine.
# This is required for the overriding of engine views and helpers to work correctly.
MyBigFancyEngine::ApplicationController.helper Rails.application.helpers
end
end
end
The RailsAdmin Engine is also isolated, but they have the same configuration options as you would like to implement. They have configurable before_filters for both authentication and authorization. Have a look at this.
As far as I can tell, they just subclass the parent controller like this::ApplicationController or instead you can configure one (ref).
For your controller you could just create your own EngineController, that inherits from RocketPant::Base and maybe just create a method there that calls the configured authentication method directly via send on the parent controller.
As the RocketPant::Base Class does not inherit from ApplicationController::Base I guess you have to find some custom way around this and can't go the normal ways for Rails Engines. Maybe you could also try to file an issue to the rocket_pant repo, to add the helper method. As far as I read they soon want to inherit from ApplicationController::Base anyway in 2.0 (ref).
I think you impulse on keeping the isolation is good - because a solution that relies on a method 'just being there' is a pain to debug if s.th. goes wrong in the app using your gem (i.e. typo in method name).
Further if your gem evolves, an some day it won't need the method, in an explicit way it's very convient to give a meainingful error:
You could provide a config method to be called in an initializer:
YourGem.configure do |config|
config.add_callback { MyApp.doIt() }
end
I found this discussion particularly insightful. There are also some interesting ideas in the Rails Engine API under Isolated engine helpers.
The Rails Engine API docs helped me figure out a good solution for url_helpers
You probably moved on by now, but if anyone else needs access to the "parent app" application helpers. You could always just include it explicitly in the application controller in your engine. like so:
include Rails.application.helpers
What I've run into is this:
AlchemyCMS is a Rails Engine for allowing Rails applications to have a Content Management System. It also has a preview page where it can load up an iframe of the example page with the layout. The layout here is the Spree layout. I've modified Alchemy to be able to load up the spree application layout and not its default.
In doing so, it is not loading up the helper methods. I am currently receiving:
undefined local variable or method `title' for #<#<Class:0x007f8dcc359498>:0x007f8de17dd6a8>
Where title is the first helper method in the application.
I've tried 5000 different techniques to try to load in Spree's helper methods into AlchemyCMS and I just can't do it.
Does anyone know how?
Ben,
You could do so by either including Spree's helpers within your application controller or within the base Alchemy controllers.
There is an extension for alchemy and spree together, which does a similar thing here:
https://github.com/magiclabs/alchemy_spree/blob/master/app/controllers/spree/base_controller_decorator.rb
You will just want to go in the opposite direction so instead of decorating a Spree controller to add Alchemy in you would decorate Alchemy controllers to include whichever of Spree's controller helpers you need to use:
https://github.com/spree/spree/blob/master/core/app/controllers/spree/base_controller.rb
In this case you need to include the common controller helpers:
https://github.com/spree/spree/blob/master/core/lib/spree/core/controller_helpers/common.rb
EDIT:
Alchemy::BaseController.class_eval do
include Spree::Core::ControllerHelpers
include Spree::Core::ControllerHelpers::Store
helper Spree::Core::Engine.helpers
end
I'm working with an existing Refinery CMS app for a client that has many controllers in many different places. If you are n00b to Refinery CMS, you can nest entire rails apps INSIDE the vender folder and they act like plugins. Its complex how it works and even worse a lot of the models/controllers are embedded in the refinery gem so a controller might exist but theres not file for it.
I wanted to extend a controller by following this example:
http://refinerycms.com/edge-guides/extending-controllers-and-models-with-decorators
which I did but my code was not firing. I did actually fix this so my problem is solved but in the future it would be useful to know what controller called this view I have. The view is tucked away in the gem HOWEVER a partial that it references was already overridden so I could throw something like:
<%= raise self.class.to_yaml %>
The problem with this I get the following error:
can't dump anonymous class: #<Class:0x000000061f5850>
Which isn't very helpful.
My question is this: How can I output the class name of the controller that calls any given view/partial ?
Thanks!
You can use params[:controller]
And params[:action] for current action
I would to nest some helper methods to simplify my application_helper, for example I have a bunch of methods dealing with currencies which apply for the entire app and I would like to put in the currencies_helper and then simply include that entire helper into the application helper.
How can I do this?
I tried:
helper :currencies
and got
undefined method `helper' for ApplicationHelper:Module
Helpers in rails are just modules which get included in controllers to help share functionality between them. There's been some weirdness around helpers in rails 3, so depending on what version you're running things may or may not work as you expect out the box.
Essentially what you want to do is add helper :all to your application_controller which will include ALL helpers in ALL your controllers. If this isn't what you want you can specify the specific helpers you want helper :currencies for example.
In the rails 3 betas helper :all was the default behavior, but I think they've reverted that in the latest release.
There's a great article that discusses how this works in rails 2, but there may be differences in rails 3, but it should be a good starting point.