flyingarmadillo
flyingarmadillo

Reputation: 2139

where to put helper methods for controllers only?

I am looking to write certain methods for processing strings, and other tasks that take place in numerous of my controllers. I know its bad practice to include helpers in your controller, so I was just wondering, where is the best place to put application wide methods used in controllers?

I realize some of you will say to put them in models, but you have to realize that not all my controllers have an associated model. Any and all input would be appreciated.

Upvotes: 21

Views: 11913

Answers (6)

Seybo Glaux
Seybo Glaux

Reputation: 787

Starting from Rails 4 there is a dedicated folder for it app/controllers/concerns. So you can create a module there and then include it in a specific controller(s) or in ApplicationController if you need it available throughout all your controllers.

Upvotes: 1

Sandip Ransing
Sandip Ransing

Reputation: 7733

If you need to use a method in the application scope then I would suggest that you keep those methods inside the application controller and in order to use them inside views.. declare those as helper methods.

For example,

class ApplicationController < ActionController::Base
 helper_method :current_user, :some_method

 def current_user
   @user ||= User.find_by_id(session[:user_id])
 end

 def some_method
 end
end

Upvotes: 11

Haris Krajina
Haris Krajina

Reputation: 15276

I would suggest to put them in lib folder. So for example I have:

lib/utils/string_utils

module StringUtils

  def foo
     ...
  end
end

class BarController < ActionController::Base
  include StringUtils
end

This demonstrates good methodology called Fat model, Thin controller, in this case we are using Mixins instead of Models to separate logic but idea is same. You want your controllers as simple as possible.

Upvotes: 9

melekes
melekes

Reputation: 1888

It all depends on your needs. I will provide here 2 examples. Both of them are just a custom libraries, located under lib directory.

First example - "custom string processing"

# lib/filters.rb
module Filters

  # Converts value to canonical view
  def self.phone(value)
    # remove all non-digits
    clean_value = value.gsub(/\D/, '')

    country_codes = configus.phone.country_codes
    area_code = configus.phone.defaults.area_code

    case clean_value.length
      when 7
        "#{area_code}#{clean_value}"
      when 11
        # remove country code only if phone starts with the allowed country code
        if country_codes.include?(clean_value[0].to_i)
          clean_value[1..-1]
        else
          clean_value
        end
      else clean_value
    end
  end

# usage
# app/api/phones_controller.rb
class Api::PhonesController < Api::ApplicationController

  def exists
    if params[:q]
      clean_value = Filters.phone(params[:q])
      ...
    end
  end
end

Second example - helper for flash messages

# lib/flash_helper.rb
module FlashHelper
  def flash_translate(key, options = {})
    scope = [:flash, :controllers]
    scope += params[:controller].split('/')
    scope << params[:action]

    t(key, {:scope => scope}.merge(options))
  end
end

# app/application_controller.rb
class ApplicationController < ActionController::Base
  include FlashHelper
end

# usage
# app/your_controller.rb
class YourController < ApplicationController

  def create
    @object = Object.new(params[:object])

    if @object.save
      flash[:success] = flash_translate(:success)
      ...
    end
  end
end

Note: do not forget to add lib dir to the autoload paths. In config/application.rb add/modify this line config.autoload_paths += %W(#{config.root}/lib). So for me the answer is lib directory.

Upvotes: 3

Simon Perepelitsa
Simon Perepelitsa

Reputation: 20639

I tend to put them into helpers. The fact that they are included in views automatically haven't been a problem for me. You can also place them into something like app/concerns/ or lib/

I don't like cluttering ApplicationController with private methods because this often becomes a mess.

Example:

module AuthenticationHelper
  def current_user
    @current_user # ||= ...
  end

  def authenticate!
    redirect_to new_session_url unless current_user.signed_in?
  end
end

module MobileSubdomain
  def self.included(controller)
    controller.before_filter :set_mobile_format
  end

  def set_mobile_format
    request.format = :mobile if request.subdomain == "m"
  end
end

class ApplicationController
  include AuthenticationHelper
  include MobileSubdomain
end

Upvotes: 13

davids
davids

Reputation: 6371

In case those methods are used in numerous controllers, I would define them in application_controller.rb. Every controller will inherits from it and will be capable to use any method defined there

Upvotes: 0

Related Questions