Add method to a gem's helpers - ruby-on-rails

I am using a gem which adds a number of View helpers under the following module hierarchy:
module Ransack
module Helpers
module FormHelpers
def search_form_for
end
end
end
end
ActionController::Base.helper Ransack::Helpers::FormHelper
I want to add my own helper method into the same module hierarchy, and make it available to all views. How do I do this?

What's the point of altering the gem with additional methods? If it's a view helper, simply create an appropriate file in the app/helpers directory of your app and add your custom helper there.
The custom helper will be available to all views.

Related

How to use a rails helper in a PDF template inside services layer?

I have a PDF template and I need to use a view helper method inside a HTML file that is in the services folder to generate the PDF. However, when I try to use the default view helpers, I get an exception that the method doesn't exist.
ActionView::Template::Error: undefined method `helper_method' for #<#<Class:0x000000000e309bd0>:0x000000000e3a0350>
How can I make this work?
You can make your module methods work as they were class methods by using
module_function :method
The code looks like this:
module Helper
def helper_method; end
module_function :helper_method
end
Then in your html.erb you do this:
<% Helper.helper_method %>

Are application helper methods available to all views?

Rails 4.1
Ruby 2.0
Windows 8.1
In my helpers/application_helper.rb, I have:
def agents_and_ids_generator
agents = Agent.all.order(:last)
if agents
agents_and_ids = [['','']]
agents.each do |l|
name = "#{l.first} #{l.last}"
agents_and_ids << [name,l.id]
end
return agents_and_ids
end
end
In my views/agents/form.html.erb, I have the following:
<%= f.select :agent_id, options_for_select(agents_and_ids_generator) %>
In my controllers/agents_controller.rb, I have the following:
include ApplicationHelper
But when I go to this view, I get the following error message:
undefined local variable or method `agents_and_ids_generator' for #<#:0x00000006fc9148>
If I move the agents_and_ids_generator method to the helpers/agents_helper.rb, it works fine.
I thought that by putting methods in the application helper and including the application in a controller, then these methods are available to the views. Am I incorrect in that assumption?
Answer:
Making sure that application helper is not included in controllers, and added the following simplification:
<%= f.collection_select :agent_id, Agent.all.order(:last), :id, :name_with_initial, prompt: true %>
#app/models/agent.rb
Class Agent < ActiveRecord::Base
def name_with_initial
"#{self.first} #{self.last}"
end
end
Helpers
The bottom line answer is the application_helper is available in all your views.
Rails actually uses helpers all over the place - in everything from the likes of form_for to other built-in Rails methods.
As Rails is basically just a series of classes & modules, the helpers are loaded when your views are rendered, allowing you to call them whenever you need. Controllers are processed much earlier in the stack, and thus you have to explicitly include the helpers you need in them
Important - you don't need to include the ApplicationHelper in your ApplicationController. It should just work
Your Issue
There may be several potentialities causing the problem; I have two ideas for you:
Is your AgentsController inheriting from ApplicationController?
Perhaps your inclusion of ApplicationHelper is causing an issue
Its strange that your AgentsHelper works, and ApplicationHelper does not. One way to explain this would be that Rails will load a helper depending on the controller which is being operated, meaning if you don't inherit from ApplicationController, the ApplicationHelper won't be called.
You'll need to test with this:
#app/controllers/application_controller.rb
Class AgentsController < ApplicationController
...
end
Next, you need to get rid of the include ApplicationHelper in your controller. This only makes the helper available for that class (the controller), and will not have any bearing on your view
Having said this, it may be causing a problem with your view loading the ApplicationHelper - meaning you should definitely test removing it from your ApplicationController
Method
Finally, your method could be simplified massively, using collection_select:
<%= f.collection_select :agent_id, Agent.all.order(:last), :id, :name_with_initial, prompt: true %>
#app/models/agent.rb
Class Agent < ActiveRecord::Base
def name_with_initial
"#{l.first} #{l.last}"
end
end
Rails 5 update. I ran into a similar issue with views not picking up a method from application_helper.rb. This post helped me. The files that are provided in the helpers directory of a new rails app are for those views only. Methods in the application_helper.rb will not be available automatically to all views. To create a helper method that is available to all views, create a new helper file in the helper directory such as clean_emails_helper.rb and add your custom method here like this:
Module CleanEmailsHelper
def clean_email(email)
*do some stuff to email*
return email
end
end
Then you can call <%= clean_email(email) %> from any view in your app.

Is there a way to render an engine's 'super' view within the main app's overridden view?

I am developing an engine with a controller and views, but I want to allow for the views to be overridden (this is simple enough as Rails::Engine allows for this by automatically prepending app/views from the main app to the view path for the engine). However, I want the overridden view to be able to refer to the view from the engine - for example, I want to "wrap" the engine's view with custom stuff in my app:
# main_app/app/views/engine/template.haml
# ... custom stuff here
= render template: 'engine/template'
# ... custom stuff here
The problem is, I can't find a way to refer to the engine's view once I override it... is it possible?
Try rendering the file by providing the full path of the engine's template file.
# in view
<%= engine_view {|f| render file: f} %>
# in helper
def engine_view(&b)
yield eval("__FILE__.gsub(Rails.root.to_s, YourEngine::Engine.root.to_s)",b.binding)
end
tihom's approach is good, but the block feels unnecessarily hacky (and rubocop won't like it). I prefer something like:
## in helper
def render_engine_view
render file: caller_locations.first.path.gsub(Rails.root.to_s, YourEngine::Engine.root.to_s)
end
## in view
# ... custom stuff here
<%= render_engine_view %>
# ... custom stuff here

Ruby on Rails - using helpers in html.erb

I'm probably missing some things.
Say for example I have a helper function in app/helpers/foo_controller.rb and the code is as follows:
def sample_helper(count)
#implementaton...
end
and I want to use this helper in a webpage generated by rails and the code is as follows:
<%= sample_helper(user.id) %>
and if I try to run the webpage it will throw me an error saying that the method is not defined.
Thanks in advance!
You don't quite have the naming conventions right.
Name your helper file app/helpers/foo_helper.rb and in it you should have this:
module FooHelper
def sample_helper(count)
"#{count} items" # or whatever
end
end
And now, from any view rendered by FooController you should be able to use the sample_helper method.
Also, you should know that if you use the rails generators this structure is setup for you. All you need to do is add methods to the files that get generated. That way you don't need to guess the naming conventions.
For example, this command will make a controller file, controller test files, a helper file, and and an index view file, all ready for you to customize.
rails g controller foo index
Is your helper should be in a file called app/helpers/foo_helper.rb that contains a a module of the same name as the helper (camelized) Like:
module FooHelper
def sample_helper(cont)
# implementation
end
end
That's the way Rail auto loads helpers.

Why do I need to include a helper twice in order to access it in the mailer and its view?

In order to get my mailer and the view to render correctly, I have to do the following:
include ::KamilHelper
add_template_helper(KamilHelper)
since i use the method do_it() both here:
class Notifier < ActionMailer::BAse
def run_it
do_it()
end
end
and in its corresponding view:
<%= do_it() %>.
Otherwise, I get:
undefined method `do_it' for #<Notifier:0x00000102b24af0>
for the view or the mailer?
Are you doing include ::KamilHelper in a controller? If so, this includes the methods from the helper into the current class (e.g. the controller), but methods from a controller are not available in a view. add_template_helper makes those methods available to templates rendered from the current controller (by calling include ::KamilHelper inside the modules that are available to the view templates).

Resources