Overriding ApplicationHelper? - ruby-on-rails

There is an ApplicationHelper in an engine we're using that looks like this:
module ApplicationHelper
def page_title()
# ...
end
end
This gets called by a number of views in the engine. I'd like to override this method in my application to provide a different default title. How do I do this? Simply defining my own ApplicationHelper didn't seem to work.

Did you define the page_title method in your ApplicationHelper module? Just having an ApplicationHelper by itself won't do it.
By default, your ApplicationHelper module should already be in app/helpers/application_helper.rb. Your app files are required by rails after it requires the plugins you are using. That means any method you define in app/helpers/application_helper.rb should override methods defined in the plugins code.
This behavior arises out of ruby's open class structure. Any time, anywhere any class/module/object can be reopened to add methods and attributes to it. More or less.
Could you post some of the code you are trying to override the engine method with?

Are other methods defined in your ApplicationHelper available?
If yes, the engine helper is probably loaded before your ApplicationHelper, and your method overwritten.
If no, Rails may never have loaded your module because it thinks it already knows about ApplicationHelper and doesn't try to load it again.

Related

Rails autoload module when application started

i have module Mymodule,inside lib directory, within few methods inside
module Mymodule
def usefull_meth(a,b)
a+b
end
end
i want to autoload it when my app started
i have inside my application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/*"]
but i still need to include it like include Mymodule
i want to use my usefull_meth(a,b) inside application helper without inclusion
how i can achieve my goal? or i have done something wrong?
I simply want to have usefull_meth anywhere in my helpers,i do not need Mymodule.usefull_meth or smth else
but i still need to include it like include Mymodule
This is how Ruby works, it has nothing to do with Rails autoload.
In order to use some method globally, you should put it into global namespace. Just remove module definition and leave only method definition in that file(even though I don't understand why don't you put it into helper directly).
I achieved what i wanted
inside application.rb
require './lib/my_module'
include Mymodule
and now i have necessary methods with out include Mymodule

Access Main App Helpers when overridings a Rails Engine View/Layout

I have created a simple Rails Engine to provide some general functionality(photo gallery) to an application. I want to be able to override the standard _header partial so that the menu for the gallery matches that of my main application. In my header view I call a helper that is part of application_helpers (main app), but I keep getting "undefined method" errors. From what I can tell the main app application_helpers are not being included (obviously) when I override the engines application layout or its partials.
So my question is, how do I override an engine view in the main application, and get access to the main application helper methods? I would still need access to the engine helpers as well as not to screw up the engine functionality.
Do I need to override the controllers as well? seem like a lot just to get some helpers.
Thanks
Rails 3.1.3
check out this blog post: http://www.candland.net/2012/04/17/rails-routes-used-in-an-isolated-engine/
The author adds a method_missing definition to the application helper in order to access the parent application's helpers.
/config/initializers/blogit.rb
module Blogit
module ApplicationHelper
def method_missing method, *args, &block
puts "LOOKING FOR ROUTES #{method}"
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
main_app.send(method, *args)
else
super
end
else
super
end
end
def respond_to?(method)
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
true
else
super
end
else
super
end
end
end
end
Try including the main app helper methods. For instance:
class MyEngineClass
include ApplicationHelper
#...
end
You may possibly need to require the file first, though I would expect Rails to correctly find it in this case.
Once ApplicationHelper is included, you should be able to directly use those helpers in the controller.
It also looks like you can call ClassName.helper("application") for a lot of Rails classes -- not sure if that will work here.
try creating a helper in your application with the same name of the helper in your engine in order to override engine helper methods.
I found this discussion particularly insightful. There are also some interesting ideas in the Rails Engine API docs under Isolated engine helpers.
Engines are supposed to be independent from the main app, that is why you can't access its helpers from the Engine.
However, there are hack-ish ways for giving your engine access to the helpers of the main app. This is how I did it:
# In the main app
# initializers/share_helpers_path_with_engine.rb
PhotoGallery::Engine.class_eval do
paths["app/helpers"] << File.join(File.dirname(__FILE__), '../..', 'app/helpers')
end
You need of course to change PhotoGallery to the actual name of your engine class.
Feel free to take a look at the Engines documentation (section about the paths): http://edgeapi.rubyonrails.org/classes/Rails/Engine.html
Disclaimer: I've only used this solution in Rails 3.2 engines.
If, in your engine you have a standard header partial vendor/gems/my_gallery_engine/app/views/application/_header.html.erb.
Then, override it in your main app by creating a customized partial app/views/application/_header.html.erb.
The override works because Rails' view template search path (by default) starts with the main apps' app/views directory, and then searches through engines' app/views in load order.
All of your main app's Helpers will be available in the partial.

Using restful path helper methods in a separate lib

In a certain module that I am using in my application, I would like to use the method alarm_path(alarm). How can I include this method in my current module?
I already tried to include ActionView::Helpers::UrlHelper, though, it still complain that this method does not exists.
Simply add this instead of your current include:
include Rails.application.routes.url_helpers

Some question about classes in plugin

I am using Ruby on Rails 3 and and I am trying to implement a new plugin. In order to learn, I am viewing inside and I am studying some popular plugins.
What I choosed is WillPaginate and in a its file there is something like this:
module WillPaginate
class << self
...
end
end
if defined? Rails
WillPaginate.enable_activerecord if defined? ActiveRecord
WillPaginate.enable_actionpack if defined? ActionController
end
I would like to know
Why the if defined? Rails statement is outside the module statement? When will be run istructions inside that?
What means and how can\should I use class << self?
module WillPaginate defines Ruby name scope and groups these methods so they can be later included with one call into some class. The if defined? Rails is outside the module because the code inside that if might include the whole module into some ActiveRecord class. And the if is executed exactly at the time when will_paginate.rb file is loaded.
All methods in that block are class methods. So later it is possible to make calls like YourModelClass.foo.
The if defined? Rails block is evaluated at load time, ie during require 'will_paginate'. That allows will_paginate to be used with or without Rails.
The class << self section is a way to define a group of methods on the WillPaginate module without having to define them all as def self.method_name. Either way works (except for a few edge cases I can't remember now), so it's mostly just a style choice.

Ruby Module Include Question

I have a CommonFunctions Module inside the lib/ folder. I have a Question Model, which includes the CommonFunctions module. Now I am trying to access the favorite function of the CommonFunctions like Question.favorite. But I am getting NoMethodError. I have included the code. Can anyone please tell me where I am doing the mistake
Error
NoMethodError: undefined method `favorite' for Class:0x00000100e11508
Inside lib/CommonFunctions.rb
module CommonFunctions
def favorite(object_id)
end
end
Inside app/models/Question.rb
require 'lib/CommonFunctions.rb'
class Question
extend CommonFunctions
end
I am executing the following code from the script/console
Question.favorite(1)
Thanks
This was a duplicate of How do I properly include a module and call module functions from my Rails model?
Your code is correct. Make sure you have the current version of the classes loaded in the console (try reload!).
As a sidenote: if you rename CommonFunctions.rb to common_functions.rb, it will be autoloaded by rails and you don't need the require.
The module method is an instance method when you want it to be a class method. Use the code below instead
module CommonFunctions
def self.favorite(object_id)
end
end
Using the word "self" defines the method as a class method (or static)

Resources