How to access ApplicationHelper methods in namespaced views? - ruby-on-rails

I have a module ApplicationHelper in app/helpers/application_helper.rb
defined like this
module ApplicationHelper
def some_method(arg)
end
end
and i have my view file is here
app/views/v1/admin/messages/show.json.jbuilder
So i am trying to access the
some_method()
in view file but it doesn't reflect!
Is this due to namespacing? or what i am not able to understand.
It would be Great if someone explains the concept.
Thanks in advance!
it says undefined method error
what could be the reason?

You didn't include your controller code, but we'll assume it ultimately inherits from ActionController::API (as it should it if it is an API controller). If so, that is the root of it rather than namespacing, etc. Per the ActionController documentation:
An API Controller is different from a normal controller in the sense
that by default it doesn't include a number of features that are
usually required by browser access only: layouts and templates
rendering, flash, assets, and so on. This makes the entire controller
stack thinner, suitable for API applications. It doesn't mean you
won't have such features if you need them: they're all available for
you to include in your application, they're just not part of the
default API controller stack.
One of the side effects of the thinner API controller is that they don't automatically include helpers like a standard Rails controller. You can easily add that back in, though.
messages_controller.rb
class Api::V1::MessagesController < ActionController::API
include ActionController::Helpers
helper ApplicationHelper
def show
# whatever
end
end
app/helpers/application_helper.rb
module MessagesHelper
def some_method(arg)
# whatever
end
end
app/views/messages/show.json.jbuilder
json.bogus do
thing1: some_method('banana')
end
If you have lots of API controllers, you can of course stick it in a base controller class they all inherit from like so:
class Api::V1::ApiController < ActionController::API
include ActionController::Helpers
helper ApplicationHelper
end

Related

Dynamic concerns with inheritance not loading twice, but only once

We are loading code dynamically with concerns, based on some environment variables, which works pretty nice.
Something like this:
# User class
class User
include DynamicConcern
end
module DynamicConcern
extend ActiveSupport::Concern
included do
if "Custom::#{ENV["CUSTOMER_NAME"].camelize}::#{self.name}Concern".safe_constantize
include "Custom::#{ENV["CUSTOMER_NAME"].camelize}::#{self.name}Concern".constantize
end
end
end
# custom code
module Custom::Custom123::UserConcern
extend ActiveSupport::Concern
included do
...
end
end
We are using this since years and it worked absolutely fine in models. Some days ago we tried to use the same approach with Controllers, but realized that this approach doesn'
t work fine with inheritance, where the parent class inherits the concern as well as the inherited class:
class ApplicationController < ActionController::Base
# this gets loaded and includes the right dynamic module
include DynamicConcern
end
class ShopController < ApplicationController
# this is NOT getting loaded again and skipped,
# since it has been loaded already in the parent controller
include DynamicConcern
end
Is there a way to tell rails that it should include/evaluade the concern a second time, since the second time it would have another class name which would include another module?
I'm not looking for other solutions, since a lot of our code is based on this approach and I think it's possible to solve this without rewriting everything.
Thanks!
You are only trying to dynamically include modules based on the class name.
It's not necessary to make a concern but it can be a normal class, and the include action can be a normal method. Every time you want to call it, just call it like any other method.
Because you have already written your code with ActiveSupport::Concern in an include fashion. I guess the following refactor may work even though I cannot guarantee it. The idea is simple:
Just make it a normal method with the target class as the parameter. You can include it (it automatically calls dynamic_include in included hook).
If the module is already included in the ancestor hierarchy chain, just invoke the dynamic_include will immediately call the method and do the dynamic includes.
Please give it a try and let me know if it works for your scenarios.
module DynamicConcern
extend ActiveSupport::Concern
included do
def self.dynamic_include(klass)
if "Custom::#{ENV["CUSTOMER_NAME"].camelize}::#{klass.name}Concern".safe_constantize
klass.include "Custom::#{ENV["CUSTOMER_NAME"].camelize}::#{klass.name}Concern".constantize
end
end
dynamic_include(self)
end
end
class ApplicationController < ActionController::Base
# this gets loaded and includes the right dynamic module
include DynamicConcern
end
class ShopController < ApplicationController
# this is NOT getting loaded again and skipped,
# since it has been loaded already in the parent controller
dynamic_include(self)
end
Actually it's a feature of Rails that the same module doesn't get loaded multiple times.
We started to use the normal ruby module inclution hooks and it worked fine!
module CustomConcern
def self.included(base)
custom_class_lookup_paths = [
"#{HOSTNAME.camelize}::Models::#{base.name}PrependConcern",
"#{HOSTNAME.camelize}::Controllers::#{base.name}PrependConcern"
].map{|class_string| class_string.safe_constantize }.compact
custom_class_lookup_paths.each do |class_string|
base.send :include, class_string
end
end

Have one method that will be used in Views, Controllers and Worker in rails app. What is best place to define it?

In my rails app I have a method that will be used in different Views, Controllers and in different Workers as well so what is best place to define this method such that code would not be get repeated.
In lib directory you can create module and define a method over there so you can access that method anywhere.
Best place is Helper, define it in application_helper.rb
module ApplicationHelper
def printing
"Printing..."
end
end
and include it in ApplicationController
class ApplicationController < ActionController::Base
include ApplicationHelper
end

using devise helper methods in rails 4.1 concerns

i have a method that uses devises user_signed_in? and current_user helpers. given that this is needed for almost all controllers in the project... it seemed like a great candidate for becoming a rails concern. however, when I move the relevant code into a concern i get:
undefined method 'user_signed_in'?
I thought maybe adding include Devise::Controllers::Helpers would help... but that was to no avail.
I trimmed this down to an example that has the mentioned issue and in a controller you would need this:
include CheckIt
and in the controller concerns directory a check_it.rb that looks like this:
module CheckIt
extend ActiveSupport::Concern
include Devise::Controllers::Helpers
included do
before_action self.checkit
end
module ClassMethods
def checkit
puts "user_signed_in? #{user_signed_in?}"
end
end
end
and then, as soon as you access some aspect of that controller it will say undefined method 'user_signed_in?'

Logic for Application Layout

I am trying to make an ActiveRecord call to get information for the application layout (the default application.html.haml layout). I know I am not supposed to put logic into the layout itself, but I am unsure of where to put it.
The line of code I need run in the layout is just a simple Model call:
Client.find_by(:id => current_user.client_id)
I would suggest throwing it in helpers/application_helper.rb. I've used this in the past for things such as title helpers and body class helpers.
# helpers/application_helper.rb
module ApplicationHelper
def body_class
[controller_name, action_name].join(' ')
end
end
# views/layouts/application.slim
body class=body_class
= yield
The ApplicationController isn't for such helpers. It's mainly as support for your controllers, not your views.
It's okay if you put it in ApplicationController. And you can put controller related code to controllers/concerns folder.
'concerns/concern.rb':
module Concern
def method
# Your code here
end
end
To use a module from concerns folder include it in the controller: include Concern

Rails 3.0 Engine - Execute code in ActionController

I am upgrading my Rails plugin to be an engine that works with the latest 3.0RC1 release and I'm having a bit of trouble figuring out the best (and most correct) way to extend ActionController. I've seen this post by DHH and this question here on SO, but my question is more about how to properly call code within the ActionController.
For instance, I need to call the following within my engine's controller:
class ApplicationController < ActionController::Base
helper :all
before_filter :require_one_user
after_filter :store_location
private
def require_one_user
# Code goes here
end
def store_location
# Code goes here
end
end
I know how to properly include my two private functions, but I can't find a way to get it to properly call helper, before_filter and after_filter.
I would greatly appreciate some links or a way to make this work. I have tried naming my controller something other than ApplicationController and having the real ApplicationController extend it, but that doesn't seem to work either. I'm really up for any solution that makes the life of the engine user as easy as possible. Ideally, they wouldn't have to extend my class, but they'd have all of the functionality built into their own ApplicationController.
You may also want to look into the initializers inside your engine subclass, so you don't have to include view helpers inside your controller class. And this will give you control over the load order of these modules.
Here is what I have been using:
module MyEngine
class Engine < Rails::Engine
initializer 'my_engine.helper' do |app|
ActionView::Base.send :include, MyEngineHelper
end
initializer 'my_engine.controller' do |app|
ActiveSupport.on_load(:action_controller) do
include MyEngineActionControllerExtension
end
end
end
end
Also, another option for the action controller extension is using a mixin module. This will let you use the before_filter, after_filter, etc..
module MyEngineActionControllerExtension
def self.included(base)
base.send(:include, InstanceMethods)
base.before_filter :my_method_1
base.after_filter :my_method_2
end
module InstanceMethods
#...........
end
end
One other thing... if you create the default rails directories at the top level of your gem, you don't have to worry about requiring the helpers or controllers. Your engine subclass has access to them. So I add my application controller and application helper extensions here:
/myengine/app/helpers/myengine_application_helper_extension.rb
/myengine/app/controllers/my_engine_action_controller_extension.rb
I like this setup because it looks similar to the application_controller and application_helper in your rails app. Again, this is just personal preference, but I try to keep anything that is directly rails related, such as controllers, helpers and models inside /my_engine/app and anything that is related to the plugin in general inside /my_engine/lib
Check out this tutorial by Jose Valim for more info on initializers:
https://gist.github.com/e139fa787aa882c0aa9c (engine_name is deprecated now, but most of this doc seems up-to-date)
So, I finally figured out the solution and I hope it helps someone else.
You need to create a file in your lib directory because you are actually going to extend the class. I did myplugin/lib/extensions/action_controller_base.rb.
Then, inside of your myplugin/lib/myplugin.rb file, do the following:
require 'extensions/action_controller_base.rb'
Inside of myplugin/lib/extensions/action_controller_base.rb put the following:
require 'action_controller' # Make sure ActionController::Base is defined
ActionController::Base.class_eval {
private
def my_method_1
# Code Goes Here
end
def my_method_2
# Code Goes Here
end
}
ActionController::Base.instance_eval {
helper_method :my_method_1, :my_method_2
before_filter :my_method_1
after_filter :my_method_2
}
If you need to have view helpers, create them in the myplugin/lib/helpers directory (or anything inside of lib, the name "helpers" doesn't matter) also and add the following to the bottom of myplugin/lib/extensions/action_controller_base.rb:
require 'helpers/helper_file_1'
require 'helpers/helper_file_2'
ActionView::Base.send :include, MyHelper1
ActionView::Base.send :include, MyHelper2

Resources