I am using the mixpanel gem for my application. It acts as middleware and dynamically inserts the code into the head for any action. I'd like to be able to turn it off for specific actions (for instance, we have an action that sends an email and we'd rather not have the code there). Any ideas for how to accomplish this?
Thanks a lot.
it seems that mixpanel have updated their gem
Prevent middleware from inserting code
Note: Only applies when Rack Middleware is setup.
Occasionally you may need to send a request for HTML that you don't want the middleware to alter. In your AJAX request include the header "SKIP_MIXPANEL_MIDDLEWARE" to prevent the mixpanel code from being inserted.
$.ajax("/path/to/api/endpoint", {
headers: {"Skip-Mixpanel-Middleware": true}, // valid http headers don't allow underscores and get filtered by some webservers
success: function(data) {
// Process data here
} });
//Alternatively, you can add this line of code to your controller to temporarily disable the middleware:
Mixpanel::Middleware.skip_this_request
Taken from:
https://github.com/zevarito/mixpanel#prevent-middleware-from-inserting-code
From the Mixpanel docs:
In your application_controller class add a method to instance mixpanel.
before_filter :initialize_mixpanel
def initialize_mixpanel
#mixpanel = Mixpanel::Tracker.new("YOUR_MIXPANEL_API_TOKEN", request.env, true)
end
Since it's initialized by a before_filter you can use skip_before_filter in your other controllers to, well, skip it for certain actions, or for all except a certain action, e.g.:
class SomeController < ActionController::Base
skip_before_filter :initialize_mixpanel, :only => [ :create, :new ]
# or
skip_before_filter :initialize_mixpanel, :except => [ :update ]
end
We couldn't figure out a way to do this and ended up stripping it out (using gsub) after the fact. If anyone else has a better solution down the road I will definitely mark yours as right, I just want to close the question. Thanks
Related
What I am trying to do is pretty simple. There are multiple versions of a Rails REST API. So, there are routes like:
http://www.example.com/v1/user.json
http://www.example.com/v2/user.json
http://www.example.com/v3/user.json
What I want to do is add custom http headers to the response based on the API version endpoint that is requested.
In my config/application.rb file, I tried:
config.action_dispatch.default_headers.merge!('my_header_1' => 'my_value_1', 'my_header_2' => 'my_value_2')
I have also tried this in my config/routes.rb file:
scope path: "v1", controller: :test do
get "action_1" => :action_1
get "action_2" => :action_2
Rails.application.config.action_dispatch.default_headers.merge!('my_header_1' => 'my_value_1', 'my_header_2' => 'my_value_2')
end
But both of these snippets append custom headers to the response irrespective of the API version endpoint.
I think I can write a middleware that checks the request url and appends the response headers based on that but it sounds a bit hackish.
Is there a better way to achieve this? Preferably via config or some central piece of code?
What about using a before_action on your controllers? I imagine each API version has its own controllers? That way you could do something like:
class API::V1::BaseController < ApplicationController
before_action :set_headers
protected
def set_headers
response.headers['X-Foo'] = 'V1'
end
end
I want to cache an action and I want it to be different depending on a request param ('type').
How can I do that? I want that not only the rendering will be cached, but also the calculation and the DB requests (most of the action itself)
One possible solution would be to save the different results to a file and once created to redirect to a proxy actions for each type and render them, but that it overly complicated solution and maybe Rails has a better build-in solution.
Is it possible?
Thank you
You can use a before filter to check the param type and proceed with necessary action.
before_filter :check_params, :only => :some_action
caches_action :some_action
def check_params
if params["type"] == 'something'
query_method1
else
query_method2
end
end
I am about to implement authorization for my Rails app.
I know I can use Cancan, but in my case all the roles I have are: user and admin. I see that people always secure the models with roles (like cancan does).
My take on authorization would be to just add:
before_filter :redirect_if_not_admin :only => :create, ...
and then:
def redirect_if_not_admin
if !#user.is_admin?
redirect_to :root
end
in all my controllers and the actions I want to restrict from being accessed.
Q1. Is this in any way less secure than restricting the access to the models' attributes?
Q2. Is there a way for someone to bypass the before_filter and the redirect and access my controller code?
thanks in advance
Sure -- just add the before_filter and your redirect handler method in application_controller.rb. As long as your user model has a method "is_admin?" this will work fine.
It is as secure as any other method (in fact, it is the method used in most cases like this). The only way to bypass the before filter would be if your code allowed it. Indeed, there are sometimes cases where you want a specific controller method to be allowed, in which case you can override the application_controller.rb filters in specific controllers using the :except or :only conditions.
I have a controller in which I am caching the show action. The show action has a number of before filters for security that are meant to execute and redirect if the user is not logged in, not a member of the current group etc. These before filters are working perfectly when I have not turned on caching, but when I flip the switch to turn caching on the before filters are no longer executed (my debugger calls aren't hit).
It has always been my understanding that before filters are called for cached actions, this being the main difference between page caching and action caching. This is backed up by the Rails Caching Tutorial section on action caching which reads:
Action Caching works like Page Caching except for the fact that the incoming web request does go from the webserver to the Rails stack and Action Pack so that before filters can be run on it before the cache is served. This allows authentication and other restriction to be run while still serving the result of the output from a cached copy.
So why aren't my before filters getting called?
A bit about my setup: Rails 3.1 using Devise for authentication. I'm using the dalli gem for a memcached store.
Here is some code that summarizes my code (a lot of cruft cut out):
class GroupsController < ApplicationController
caches_action :show
cache_sweeper :group_sweeper
before_filter :authenticate_user!, :except => [:index]
before_filter :init_group, :except => [:new, :create, :index]
before_filter :requires_group_membership, :except => [:new, :create, :index]
def show
end
private
def requires_group_membership
if current_user and !#group.users_active.index(current_user).nil?
return true
else
redirect_to :root
return false
end
end
def init_group
#group = current_user.active_groups.find_by_id(params[:id])
if #group.nil?
redirect_to :root
return false
end
end
So, has anyone seen this behavior before? Do I have a hole in my understanding of how before filters and action caching is supposed to work? Or perhaps I have some weird voodo happening with a weird combo of gem versions?
[EDIT]
Interestingly I just learnt that the return value has not have an effect on the whether or not methods further along the chain are run, it is whether a redirect or render are called.
[edit 2]
I upgraded my app to rails 3.2.3 to see if it had an effect, but didn't fix the problem. Something that I have discovered is that the before filters defined in ApplicationController are getting called, but the ones in my GroupsController are not.
Well this has been a very timeconsuming way to learn a new tidbit about caching.
It turns out that you need to make the call to caches_action AFTER the before_filters that you want to run. I had placed the caches action as one of the first things in my class. This meant that all the before filters were not being run as they appeared below/after the caches_action, and caches_action halts the running of the code (and serves up the cached result).
Thanks to Pan Thomakos for his answer that contained this gem of info - which is either not in the ruby docs OR I have skimmed over it. I will endevour to have this info added to the docs once I have managed to claw back the time lost due to this little blindspot.
I am implementing a REST API which is versioned(like Twitter API), so based on version in request, I need to render template specific to the version, for example, if the client requests:
http://www.foo.com/api/v1/posts.json
I'd like to have the controller render:
posts/index.v1.json.erb
but if the client requests
http://www.foo.com/api/v2/posts.json
I'd like to have the controller render:
posts/index.v2.json.erb
and so on.
the version number in URL will be put in params hash in route.rb.
I want to do this in a reusable way, so it's not acceptable to repeat the logic in specific controller action.
I have tried view resolver, however it doesn't have access to request so there is no way I can pass the version number to resolver.
is there any way to accomplish this?
Thank you!
-Xiaotian
You can specify the version number in your routes.rb like:
map.connect '/api/:version/posts', :controller => :api, :action => :index, :version => :version
Then you would have access to the version in your controller via params[:version] and can handle it appropriately.
I think I would suggest making a separate controller for each version, maybe in the same module
Api::VersionOneConroller
Api::VersionTwoConroller
or something like that, I am not familiar with your whole app so I cannot say whether that will work, buts its something to consider.
------------update-------------
if the difference in versions in only in output foramtting or somehting, and all the actions do the same thing you could add after filters
class ExampleContrller < ApplicationController
after_filter :manage_versions
...
end
ApplicationController < ActionController::Base
protected
def manage_versions
case params[:version]
when '1.0'
#response to xml
when '1.2'
#response to json
else
# err or default to one
end
end
end
something like that could work
read more about filters here http://rails.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html