我正在尝试为我的Rails 3应用程序创建一个
JSONP API.现在在我的控制器中,我有很多遵循这种模式的动作:
# This is from my users_controller.rb,as an example def index @users = User.all respond_with(@users,:callback => params[:callback]) end
虽然这是按原样运作的,但我想通过不必重复:callback =>来干它.每个动作对respond_with的调用中的params [:callback].我怎样才能做到这一点?
更新:有一件事我已经意识到我上面的代码是丑陋的:callback => params [:callback]选项将被传递给任何响应格式,而不仅仅是JSON.以下代码可能更正确:
def index @users = User.all respond_with(@users) do |format| format.json { render :json => @users,:callback => params[:callback]} end end
我有几种方法可以解决这个问题,但我无法弄清楚如何使它们工作:
>覆盖渲染(可能在应用程序控制器中),以便它接受:jsonp选项,该选项自动包含:callback => params [:callback]参数.这样我可以将上面的代码改为以下代码,这有点短:
def index @users = User.all respond_with(@users) do |format| format.json { render :jsonp => @users} end end
>创建一个覆盖to_json的响应器以解决我的问题.这样我就可以省去块,只需调用respond_with(@users,:responder =>’MyResponder’)来解决问题.或许我可以使用plataformatec’s responders gem将此代码包含在应用程序响应程序中,以便respond_with(@users)本身就足够了.
解决方法
请注意,从技术上讲,使用回调参数呈现JSON是不正确的,因为您获得了JavaScript响应(对JSON-P回调的函数调用)而不是JSON结果.
所以,如果你有
所以,如果你有
render :json => my_object,:callback => params[:callback]
并且对/ users?callback = func的请求进来了,Rails会回答
func({…})
内容类型为application / json,这是不正确的,因为上面的响应显然不是JSON而是JavaScript.
我使用的解决方案是
def respond_with_json(item) respond_with do |format| format.json { render :json => item } format.js { render :json => item,:callback => params[:callback] } end end
无论有没有回调,它都能正确响应.将此应用于上述解决方案,我们得到:
def custom_respond_with(*resources,&block) options = resources.extract_options! if params[:callback] old_block = block block = lambda do |format| old_block.call(format) if block_given? format.js { render :json => resources[0],:callback => params[:callback] } end end respond_with(*(resources << options),&block) end
还要注意对资源[0]的更正,否则最终会因为splat运算符而将资源包装在额外的数组中.