Here's the code:
class SyncController < ApplicationController
def get_sync
#passed_ids = params[:ids].split(',')
#users = #passed_ids.collect{|id| User.find(id)}
#add the current user to the list
#users << current_user
#recommendations = get_recommendations(#users)
end
end
module SyncHelper
def get_recommendations(users)
users
end
end
I'm getting a can't find get_recommendations method error...
Your SyncHelper module needs to be included into your SyncController class. You can either add the line
include SyncHelper
in your class definition, or, if SyncHelper lives in the expected app/helpers file, you can use the rails helper method.
Related
The following universal_methods.rb file is placed in the controllers directory to contain methods to share across controllers.
class UniversalMethods
def initialise_municipal(user_params)
user_params = params[:user]
municipal_via_id = user_params[:municipal_id]
[...]
end
end
The UserController method is instantiated and contains a method calling the above:
require_dependency 'universal_methods'
class UsersController < ApplicationController
def admin_create
set_user_login_name
user_params = params[:user]
initialise_municipal(user_params)
[...]
end
I have tested that the application accesses the file (by using just require it complains of not finding if). However, the method is definitely not accessed:
NoMethodError: undefined method initialise_municipal' for #UsersController:...`
What is wrong in this syntax / setup ?
To strictly fix your code you need UniversalMethods.new.initialise_municipal(user_params) instead of just initialise_municipal(user_params) and there's no need to require the file because everything in /controllers is autoloaded.
Another approach for this is with Concerns. Create a folder app/controllers/concerns and put universal_methods.rb there.
For Rails 6
# app/controllers/concerns/universal_methods.rb
module UniversalMethods
extend ActiveSupport::Concern
included do
def initialise_municipal(user_params)
user_params = params[:user]
municipal_via_id = user_params[:municipal_id]
end
end
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController
include UniversalMethods
def admin_create
set_user_login_name
user_params = params[:user]
initialise_municipal(user_params)
[...]
end
end
I am trying to access Devise's current_user variable inside a new instance of another controller. Here is my definition of GetsInterfaceController
class GetsInterfaceController < ApplicationController
def select_current_signed_in_user
#signed_in_user_here = current_user
end
end
Then I instantiate a new instance of GetsInterfaceController in ClientsController
class ClientsController < ApplicationController
def get_current_user
#gets_interface_controller = GetsInterfaceController.new
find_signed_in_user = #gets_interface_controller.select_current_signed_in_user
end
end
But I get null error on the #signed_in_user_here = current_user line in GetsInterfaceController when I try this. Anyway to get to the current_user attribute from inside GetsInterfaceController ?
I solved this by moving my code into a Module in lib directory. Works like a charm
current_user is not a variable - it is a helper method. Thus it is already available in all your helpers and views.
Additionally you never instantiate controllers in Rails. The router does that for you.
The only public methods in your controllers should be the actions which respond to HTTP requests.
If you want to reuse a method in several controllers you should be using inheritance, modules (concerns) or helpers. Never by calling a method on another controller.
To call an external service you want to create an API client class:
# adapted from https://github.com/jnunemaker/httparty
require 'httparty'
class StackExchangeClient
include HTTParty
base_uri 'api.stackexchange.com'
def initialize(service, page, user = nil)
#user = user
#options = { query: {site: service, page: page} }
end
def questions
self.class.get("/2.2/questions", #options)
end
def users
self.class.get("/2.2/users", #options)
end
end
Or if you need to call an external service and for example create several models with the data a Service Object:
class SomeService
def initialize(user, client: SomeClient)
#user = user
#client = client # for mocking
end
def call
response = #client.get('/foo')
response.each do |d|
#user.baz << d[:woo]
end
end
end
SomeService.new(current_user).call
I have the following helper
module AvatarHelper
# Todo: set a defatul profile-image-path
DEFAULT_PROFILE_IMAGE_PATH = "http://image_here"
def avatar_path(user, size = 24)
..
end
def get_facebook_profile_pic user, size
..
end
def get_gravatar_path user, size
..
end
end
When I try to call the helper method in controller, it results in the following error:
undefined method `avatar_path' for AvatarHelper:Module
Here is my controller for reference:
class DashboardController < ApplicationController
before_action :authenticate_user!
def index
#dashboard = Dashboard.new(current_user)
puts AvatarHelper.avatar_path(current_user)
end
end
When I reference other helpers, I see they don't need to reference the helper elsewhere.
module TitleHelper
SITE_TITLE = 'My Site'
TITLE_SEPARATOR = ' ยท '
DESCRIPTION_CHARACTER_LIMIT = 140
def title(*parts)
parts << SITE_TITLE
provide(:title, parts.compact.join(TITLE_SEPARATOR))
end
end
I can then just add the title method directly in the view.
<% title 'myPage' %>
Module methods cannot be invoked directly. They should be included in the class to invoke. That's why they are called mixins(they can be mixed with others).
Here you can include the module in your controller.
class DashboardController < ApplicationController
include AvatarHelper
def index
#dashboard = Dashboard.new(current_user)
puts avatar_path(current_user)
end
end
def self.avatar_path(user, size = 24)
..
end
you are calling instance method add self before mthod will work for you.
Add the following code in your helper.
module AvatarHelper
extend ActiveSupport::Concern
Now you can directly call your method by name like
puts avatar_path(current_user)
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.
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
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
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.
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.
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.
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
How do I make the following method available in the view layer?
# app/controllers/base_jobs_controller.rb
class BaseJobsController < ApplicationController
def self.filter_name
(controller_name.singularize + "_filter").to_sym
end
end
I want to use it in a view helper like this:
module ApplicationHelper
def filter_link(text, options = {})
# Need access to filter_name in here....
end
end
Instead of helper_method, I prefer to include such functionality in a module.
module BaseJobsHelp
def filter_name
(controller_name.singularize + "_filter").to_sym
end
end
Then include the module in the BaseJobsController and ApplicationHelper.
class BaseJobsController < ApplicationController
include BaseJobsHelp
# ...
end
module ApplicationHelper
include BaseJobsHelp
def filter_link(text, options = {})
# You can access filter_name without trouble
end
end
Depending on the content of your methods in the module, you may need to use an alternative method to access certain data (ie. the current controller's name).