Add helper to rails controller instance only - ruby-on-rails

I have some helpers that are defined on runtime that are specific for a single call, e.g. a single instance of a controller (the next call could have different helper methods). Is there a robust way to add a helper method to an instance of a controller and it's view only, without adding the helper to other instances and views of this controller?
To define a helper for ALL instances, you could use the .helper_method method, e.g.
class Article < ApplicationController
helper_method :my_helper
def my_helper
# do something
end
end
I digged around in the source code, and found the (fairly private looking) #_helpers method which returns a module that contains all helpers for this instance. I could now use some meta programming to define my methods on this module
def index
_helpers.define_singleton_method(:my_helper) do
# do something
end
end
But I don't like this approach because I'm using a clearly private intended method that could easily change in the future (see the leading _).
If I only needed the helper inside the controller instance only, I could just call #define_singleton_method on the instance directly, but this doesn't make it available to the view.
So I'm looking for an official "Rails way" to define a helper for a single instance of a controller and it's view, like Rails provides with it's class method .helper_method.

I'm not sure if there is an official Rails way of doing this.
You could create an anonymous module and extend from that. Since this solution uses pure Ruby, you'll have to extend both the controller and view.
before_action :set_helpers, only: :index
def index
# ...
end
private
def set_helpers
#helpers = Module.new do |mod|
define_method(:my_helper) do
# do something
end
end
extend(#helpers)
end
<% extend(#helpers) %>

Related

Controller calls the helper

I have an easy question:
Where to put the helper methods that is called many times by a controller ?
My wish is to keep clear my controller ( user_controller) and I have an helper methods that is called many times (check_permits)
is it possible to put this method inside user_helper ?
If yes ==> how to recall it inside user_controller ? If I simply recall check_permits it doesen't recognize it.
If no ==>, where to put the helper methods ?
You are using confusing terminology. In rails, controllers do not have helpers. Helpers are defined as being for the views. It's possible to call helper methods from a controller by using the "helpers" method (see http://api.rubyonrails.org/classes/ActionController/Helpers/ClassMethods.html), but I don't think that's what you're looking for (and generally that's not a good idea anyway).
What you probably want is to either (1) put the method directly in your users_controller.rb as a protected method:
class UsersController < ApplicationController
...
protected
def check_permits
...
end
end
Or (2) put it in the application_controller.rb if you call it from multiple controllers.
Or (3) put it in a library file as a module and include it in whatever controllers need it. For example, you might create lib/check_permits.rb:
module CheckPermits
protected
def check_permits
...
end
end
And then in users_controller.rb:
class UsersController < ApplicationController
include CheckPermits
...
end
You can put global helper methods in the application_helper.rb file, but if it's only to be used by one controller each controller can have it's own helper file. Look in app/helper (or app/controller/helper).

Rails 3: Call functions inside controllers

If I want to have functions to be called inside controllers, where should I put them?
if you want it to be local to a controller then all you need to do is to add it to the controller you wish to use.
private
def myfunction
function code.....
end
to all controllers you can put it inside the application controller, because all controlers are sub classed.
ApplicationController
protected
def myfunction
function code.....
end
If you want access in your views then you can create a helper
ApplicationHelper
def myfunction
function code...
end
#jonnii, for example, I want to call a function that returns a generated unique code.
If your generated code is going to be used only on your controllers, put the function inside a controller, as protected function (the easiest way would be putting it inside ApplicationController).
If you need to call the function on the views, then put it on a helper, like ddayan says.
If you also need to invoke the function from models, then the simplest way to do it is by putting a module inside the /lib/ directory.
# /lib/my_module.rb
module MyModule
def generate_code
1
end
end
You will also need to include it with an initializer:
#/config/initializers/my_module.rb
require 'my_module'
From that moment on, you can use the function like this:
MyModule::generate_code
If you are doing this very often, consider creating a gem.
class YourController < ActionController::Base
def your_action
your_function
end
private
def your_function
end
end
Also look at before_filter and after_filter, they're often useful in such kind of things
The ApplicationController is here for that, since every Controller inherited from it.

What do helper and helper_method do?

helper_method is straightforward: it makes some or all of the controller's methods available to the view.
What is helper? Is it the other way around, i.e., it imports helper methods into a file or a module? (Maybe the name helper and helper_method are alike. They may rather instead be share_methods_with_view and import_methods_from_view)
reference
The method helper_method is to explicitly share some methods defined in the controller to make them available for the view. This is used for any method that you need to access from both controllers and helpers/views (standard helper methods are not available in controllers). e.g. common use case:
#application_controller.rb
def current_user
#current_user ||= User.find_by_id!(session[:user_id])
end
helper_method :current_user
the helper method on the other hand, is for importing an entire helper to the views provided by the controller (and it's inherited controllers). What this means is doing
# application_controller.rb
helper :all
For Rails > 3.1
# application.rb
config.action_controller.include_all_helpers = true
# This is the default anyway, but worth knowing how to turn it off
makes all helper modules available to all views (at least for all controllers inheriting from application_controller.
# home_controller.rb
helper UserHelper
makes the UserHelper methods available to views for actions of the home controller. This is equivalent to doing:
# HomeHelper
include UserHelper
A Helper method is used to perform a particular repetitive task common across multiple classes. This keeps us from repeating the same piece of code in different classes again and again.
Here's an example to simplify the above definition:
Here is a code, where you would have something like this in the view:
<% if #user && #user.email.present? %>
<%= #user.email %>
<% end %>
We can clean it up a little bit and put it into a helper:
module SiteHelper
def user_email(user)
user.email if user && user.email.present?
end
end
And then in the view code, you call the helper method and pass it to the user as an argument.
<%= user_email(#user) %>
This extraction makes the view code easier to read especially if you choose your helper method names wisely.
So I hope this clears things up a little for you.
Source for the quotation
Source for the code

How can I programatically determine which methods have been declared as "helper" methods by a controller in Rails?

I'm writing a plugin that adds a method to controllers and declares it as a helper method. If it were done statically (rather than through the plugin), it would look something like this:
# in RAILS_ROOT/app/controllers/stuffed_animals_controller.rb
class StuffedAnimalsController < ActionController::Base
private
def bear
'Teddy Bear'
end
helper_method :bear
end
# in RAILS_ROOT/app/views/stuffed_animals/index.html.erb:
<%= bear -%>
It works just fine. I want to test that :some_helper_method is actually a helper method, though. I tried this:
def test_declared_bear_as_helper_method
assert StuffedAnimalsController.helper_methods.include?(:bear)
end
Unfortunately, ActionController::Base does not have a :helper_methods class method. Anyone know where I can get the list of things a class exposes via :helper_method?
Got it!
def test_declared_bear_as_helper_method
helper = Object.new
helper.extend StuffedAnimalsController.master_helper_module
assert helper.respond_to?(:bear)
end

Rails: macro style functions

In models and controllers, we often use Rails macros like before_validation, skip_before_filter on top of the class definition.
How is this implemented? How do I add custom ones?
Thanks!
They're just standard Ruby functions. Ruby's flexible approach to syntax makes it look better than it is. You can create your own simply by writing your method as a normal Ruby function and doing one of the following:
putting it somewhere that's accessible by your controllers such as application.rb
putting it in a file and requiring it in.
mixing the code into a class via the Ruby include keyword.
That last option is great for model classes and the first option is really only for controllers.
An Example
An example of the first approach is shown below. In this example we add code into the ApplicationController class (in application.rb) and use it in the other controllers.
class BusinessEntitiesController < ApplicationController
nested_within :Glossary
private
# Standard controller code here ....
The nested_within provides helper functions and variables to help identify the id of the "parent" resource. In effect it parses the URL on the fly and is accessible by every one of our controllers. For example when a request comes into the controller, it is automatically parsed and the class attribute #parent_resource is set to the result of a Rails find. A side effect is that a "Not Found" response is sent back if the parent resource doesn't exist. That saves us from typing boiler plate code in every nested resource.
That all sounds pretty clever but it is just a standard Ruby function at heart ...
def self.nested_within(resource)
#
# Add a filter to the about-to-be-created method find_parent_id
#
before_filter :find_parent_id
#
# Work out what the names of things
#
resource_name = "#{resource.to_s.tableize.singularize}"
resource_id = "#{resource_name}_id"
resource_path = "#{resource.to_s.tableize}_path"
#
# Get a reference to the find method in the model layer
#
finder = instance_eval("#{resource}.method :find_#{resource_name}")
#
# Create a new method which gets executed by the before_filter above
#
define_method(:find_parent_id) do
#parent_resource = finder.call(params[resource_id])
head :status => :not_found, :location => resource_path
unless #parent_resource
end
end
The nested_within function is defined in ApplicationController (controllers/application.rb) and therefore gets pulled in automatically.
Note that nested_within gets executed inside the body of the controller class. This adds the method find_parent_id to the controller.
Summary
A combination of Ruby's flexible syntax and Rail's convention-over-configuration makes this all look more powerful (or weirder) than it actually is.
Next time you find a cool method, just stick a breakpoint in front of it and trace through it. Ahh Open Source!
Let me know if I can help further or if you want some pointers on how that nested_within code works.
Chris
Chris's answer is right. But here's where you want to throw your code to write your own:
The easiest way to add Controller methods like that is to define it in ApplicationController:
class ApplicationController < ActionController::Base
...
def self.acts_as_awesome
do_awesome_things
end
end
Then you can access it from individual controllers like so:
class AwesomeController < ApplicationController
acts_as_awesome
end
For models, you want to reopen ActiveRecord::Base:
module ActiveRecord
class Base
def self.acts_as_super_awesome
do_more_awesome_stuff
end
end
end
I personally would put that in a file in config/initializers so that it gets loaded once, and so that I know where to look for it always.
Then you can access it in models like so:
class MySuperAwesomeModel < ActiveRecord::Base
acts_as_super_awesome
end

Resources