I am working on adding some methods to a controller dynamically.
def self.add_command(method)
define_method(method) do
# Do something
end
end
add_command :method_name
I would like to add an around filter for these methods and only these, but do it dynamically. When I simply try to add an around_filter call in the add_command method it doesn't get triggered.
How is it possible to dynamically add an around filter?
def self.add_command(method)
define_method(method) do
# Do something
end
class_eval do
around_filter method.to_sym
end
end
Related
I have the following method in my ApplicationController:
helper_method :body_css_classes
def body_css_classes
[controller_name, action_name]
end
I have it in the controller, because I want to be able to overwrite it in other controllers like this:
def body_css_classes
super << #view
end
This works, but somehow it feels like this should be in the ApplicationHelper, not in the ApplicationController. Is there a way to move it to the helpers? As far as I can see, super won't be available there.
I have two Helpers, ExamsHelper and ResultsHelper
exams_helper.rb
module ExamsHelper
def get_data
...
end
end
results_helper.rb
module ResultsHelper
def find_result
...
end
end
Is it possible to access the get_data method in ResultsHelper.
I know that if I am declaring it on the ApplicationHelper, I can access it. Is there any other solution for it?
You can always use include:
module ResultsHelper
include ExamsHelper
def find_result
get_data # works
end
end
I want to create a method like current_user for devise's current resources.
Suppose I have two resources like User and Admin and devise is associated with both. So as usual it dynamically creates it's default methods like current_user and current_admin.
It creates it by defining like this in file lib/devise/controllers/helpers.rb:
def current_#{mapping}
How can I add a new method like this to it's dynamic methods.
I want to implement it with devise methods, so that when devise initializes then my method is also initialize with same mapping name.
Copy this code into your application controller. and your problem will solved.
Devise.mappings.each do |mapping, obj|
define_method "current_#{mapping}_email" do
eval("current_#{mapping}.email if current_#{mapping}")
end
helper_method "current_#{mapping}_email"
On view page/controller used according to your resource name
like if you have resource_name as user then its 'current_user_email'
or if have admin then 'current_admin_email'
This works!
I added a custom method current_user_email as follows!
Add a file devise_ext.rb in config/initializers:
And in that file, add your custom methods in this way:
module Devise
module Controllers
# Those helpers are convenience methods added to ApplicationController.
module Helpers
def self.define_helpers(mapping) #:nodoc:
mapping = mapping.name
class_eval <<-METHODS, __FILE__, __LINE__ + 1
def authenticate_#{mapping}!(opts={})
opts[:scope] = :#{mapping}
warden.authenticate!(opts) if !devise_controller? || opts.delete(:force)
end
def #{mapping}_signed_in?
!!current_#{mapping}
end
def current_#{mapping}
#current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
def #{mapping}_session
current_#{mapping} && warden.session(:#{mapping})
end
def current_#{mapping}_email
#current_#{mapping}.email if #current_#{mapping}
end
METHODS
ActiveSupport.on_load(:action_controller) do
helper_method "current_#{mapping}", "#{mapping}_signed_in?", "#{mapping}_session", "current_#{mapping}_email"
end
end
end
end
end
P.S. I don't think this is the best way to do this. But it works. I tried this in one of my applications! You can use this code till I find a better way to do this :)
I'm trying to add an around_filter to a controller in ActiveAdmin. I get an undefined method error when I try to add the filter. Example:
ActiveAdmin.register Event do
controller do
around_filter :my_filter
def my_filter
yield
end
end
end
When I try it out, I get:
"undefined method `my_filter' for #<Admin::EventsController:0x0000010de3a798>"
My project is using Rails 3, if that's relevant. What am I missing here?
Update: This was due to a very silly syntax error. Rather than something like the above, I had misplaced my method definition, something like this:
ActiveAdmin.register Event do
controller do
around_filter :my_filter
# lots of stuff here...
end
def my_filter
yield
end
end
so I was declaring the around filter, but defining it outside the controller.
Filter method should be inside controller
ActiveAdmin.register Event do
controller do
around_filter :my_filter
# lots of stuff here...
def my_filter
yield
end
end
end
Suppose I have some logic in a base controller to pass information to the view to build something like a breadcrumb:
class ContextAwareController < ApplicationController
after_filter :build_breadcrumb
def build_breadcumb
#...
end
end
I want this build_breadcrumb method to run after the main controller logic, but before the view is rendered.
The above code runs too late, but a before_filter would be too early.
Can anybody suggest a way to accomplish this without explicitly calling build_breadcumb at the end of each of the actions in the child controllers?
Thanks
I had the same problem and solved it like this:
class ApplicationController < ActionController::Base
def render *args
add_breadcrumbs
super
end
end
There are also some gems to achieve this. One of them is rails3_before_render.
It works similarly to filters, for example:
class PostsController < ApplicationController
before_render :ping, :except => [:destroy]
def index; end
def new; end
def show; end
def destroy; end
private
def ping
Rails.logger.info "Ping-Pong actions"
end
end
(code snipped copied from gem documentation)
I believe rendering starts when render is called, and there's no default way to defer it. Here's one thing you could do:
filters are applied in the same order declared. So make a second after-filter that calls render with an array args stored in a class variable. Then anywhere you would normally call render, set the variable.
If we're overriding render, we're not really using the filter chain at all, so it might be simpler to determine which action we're in using the #_action_name.
StuffController < ApplicationController
def my_filter
# Do the stuff
end
def render(*args)
my_filter if #_action_name == "show"
super
end
end
You can use alias_method_chain like this
alias_method_chain :render, :before_render_action
this will create 2 methods :render_with_before_render_action and :render_without_before_render_action. If you call render, then :render_with_before_render_action will be called. You can override this method
def render_with_before_render_action(*options, &block)
<your code>
render_without_before_render_action(*options, &block)
end
If you don't want your code to be executed and you want to have default render then you should directly call the :render_without_before_render_action
You can do like this to fake a before_render:
class StuffController < ApplicationController
before_filter :my_filter, only: [:index, :show]
def my_filter
#my_filter = true
end
def _my_filter
# Do the actual stuff here
end
def render(*args)
_my_filter if #my_filter
super
end
end
Thanks to #joshua-muheim for the tip about using render