I'm trying to create a JSONP API for my Rails 3 application. Right now in my controllers, I have a lot of actions which follow this pattern:
# This is from my users_controller.rb, as an example
def index
@users = User.all
respond_with(@users, :callback => params[:callback])
end
While this works as is, I would like to DRY it up by not having to repeat the :callback => params[:callback] in every action's call to respond_with. How can I do this?
Update: One thing I've realized that is ugly about my above code is that the :callback => params[:callback] option will be passed for any response format, not just JSON. The following code is probably more correct:
def index
@users = User.all
respond_with(@users) do |format|
format.json { render :json => @users, :callback => params[:callback]}
end
end
There are a couple ways I've considered to address this problem, but I can't figure out how to make them work:
- Override
render(perhaps in the application controller) so that it accepts a:jsonpoption that automatically includes the:callback => params[:callback]parameter. This way I could change the above code to the following, which is somewhat shorter:
def index
@users = User.all
respond_with(@users) do |format|
format.json { render :jsonp => @users}
end
end
- Create a responder that overrides
to_jsonin order to solve my problem. That way I could leave out the block and just callrespond_with(@users, :responder => 'MyResponder')to solve the issue. Or perhaps I could include this code in an application responder using plataformatec's responders gem so thatrespond_with(@users)by itself would be sufficient.
Thanks to samuelkadolph for helping me in the #rubyonrails IRC channel today. He provided a solution in this gist, copied below for convenience:
I haven't tried this in my application yet, but I can see that it should work. He also confirmed that I could similarly override the
respond_withmethod itself simply by changing the name of this method and changing the last line of the definition tosuper(*(resources << options), &block).I think this will work for me. However, I'm still interested in knowing how to write a custom responder to do the job. (It would be a more elegant solution, IMHO.)
Update: I tried this in my application and it works with some minor changes. Here is the version I'm using now in the
privatesection of my ApplicationController, designed to automatically provide the:callback => params[:callback]option to JSON requests:Note that I had to change
if options[:callback]toif params[:callback]in order to get it working.