wechat icon indicating copy to clipboard operation
wechat copied to clipboard

与rails 5/6存在冲突,不知道是哪一方有问题

Open freefishz opened this issue 7 years ago • 13 comments

rails 5 + jbuilder 2.6 + WeChat 0.8.3, 会导致api json输出body部分为空。具体问题见以下链接https://github.com/rails/jbuilder/issues/346中charleyw的回复。

freefishz avatar Dec 01 '16 05:12 freefishz

@charleyw 我的理解是如果使用了jbuilder,还使用了WeChat,会导致jbuilder输出问题?我自己的项目已经用了jbuilder 2.6.1,似乎没有这个问题?测试也无法复现,能给个可复现的例子么?最好是rspec的failure的测试。

Eric-Guo avatar Dec 01 '16 06:12 Eric-Guo

昨天用pry-byebug跟踪了一下,发现不是jbuilder的问题,是和rails5有冲突。 在 wechat_responder.rb,中添加

  if defined? Base
    class << Base
      include WechatResponder
    end
  end

  if defined? API
    class << API
      include WechatResponder
    end
  end

后,在controller中查看祖先链时,发现少了ActionView::Rendering,导致了不能render正确的模板。ActionView::Rendering中有个方法_normalize_options,用于设置render的模板(jbuilder的模板)。如果缺少了这个模块,就会再往上调用祖先的_normalize_options,就会导致模板丢失,也就不render了。

=> [Api::V1::HomesController,
 #<Module:0x000000061d6d10>,
 Api::V1::ApplicationController,
 Knock::Authenticable,
 #<Module:0x00000006231300>,
 #<Module:0x000000064458d0>,
 #<Module:0x000000064458f8>,
 ActionController::API,
 ActionController::ImplicitRender,
 ActionController::Helpers,
 AbstractController::Helpers,
 ActiveRecord::Railties::ControllerRuntime,
 ActionDispatch::Routing::RouteSet::MountedHelpers,
 ActionController::ParamsWrapper,
 ActionController::Instrumentation,
 ActionController::Rescue,
 ActionController::DataStreaming,
 ActionController::ForceSSL,
 AbstractController::Callbacks,
 ActiveSupport::Callbacks,
 ActionController::StrongParameters,
 ActiveSupport::Rescuable,
 ActionController::BasicImplicitRender,
 ActionController::ConditionalGet,
 ActionController::Head,
 ActionController::Renderers::All,
 ActionController::Renderers,
 ActionController::Rendering,
 ActionController::ApiRendering,
 -------就是这个> ActionView::Rendering,
 ActionController::Redirecting,
 ActiveSupport::Benchmarkable,
 AbstractController::Logger,
 ActionController::UrlFor,
 AbstractController::UrlFor,
 ActionDispatch::Routing::UrlFor,
 ActionDispatch::Routing::PolymorphicRoutes,
 AbstractController::Rendering,
 ActionView::ViewPaths,
 #<Module:0x00000003381fc8>,
 ActionController::Metal,
 ActionController::Testing::Functional,
 AbstractController::Base,
 ActiveSupport::Configurable,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 PP::ObjectMixin,
 ActiveSupport::Dependencies::Loadable,
 JSON::Ext::Generator::GeneratorMethods::Object,
 ActiveSupport::Tryable,
 Kernel,
 BasicObject]

如果注释掉wechat_responder.rb中的那段代码,ActionView::Rendering就回来了。 而且发现,只要在wechat_responder.rb中将对上述注释掉的代码改为仅打开API,也会出现同样的问题,比如:

module ActionController
  class API 
  end
end

至于为何会导致ActionView::Rendering丢失,还在研究。

freefishz avatar Dec 02 '16 02:12 freefishz

刚才看了一下,这个问题只有在rails 5的API模式下才能重现。

charleyw avatar Dec 02 '16 08:12 charleyw

我也遇到了同樣的問題,但沒有使用你們的 wechat gem。

我是把原本 app 裡面繼承 ActonController::Base 的 api 改成繼承 ActionController::API 從而發現問題。從頭 rails new 一個 app 則沒有這個問題。

yorkxin avatar Dec 09 '16 05:12 yorkxin

我的环境是rails5 API的,也遇到了类似的问题 如果直接在controller里引用wechat_api,启服务时则会提示找不到 undefined local variable or method wechat_api' for XxxController:Class`

如果把继承换成ActionController::Base则没问题,但是不能那么干:) 看了源码后,有样学样加了这样一段在controller里,就能通过了 module ActionController class << API include WechatResponder end end

那么有两个问题:

  1. 在wechat_responder.rb中,以下这段代码明显是把include默认加到了ActionController::Base中而不是API,这个是为啥? if defined? Base class << Base include WechatResponder end elsif defined? API class << API include WechatResponder end end

  2. 如果我不是把include加在ActionController::API中而是直接放到我自己的controller中,则会提示``class:XxxController': uninitialized constant WechatResponder (NameError)`这是为什么?

xwangzhaox avatar Dec 15 '16 07:12 xwangzhaox

暂时可以通过手工添加include ActionView::Rendering来解决这个问题:

class ApplicationController < ActionController::API
  include ActionView::Rendering
end

freefishz avatar Jan 05 '17 02:01 freefishz

这个问题暂时还没解决,引入 wechat 这个 gem 后,jbuilder 的输出就是空的,引入 include ActionView::Rendering 后,能解决 jbuilder 的问题,但是 render json: {ok: 1} 这种又不能用了。。

个人认为,插件最好不要修改框架底层的东西

numbcoder avatar Jun 07 '17 03:06 numbcoder

wechat (0.8.8)出现同样的问题 会退到wechat (0.8.4)就好了

mysterytree avatar Jun 08 '17 03:06 mysterytree

@mysterytree 能在本地改一下最新0.8.8的这几行确认一下么?

bundle open wechat # edit lib/action_controller/wechat_responder.rb:L66

  if defined? Base
    class << Base
      include WechatResponder
    end
  elsif defined? API
    class << API
      include WechatResponder
    end
  end

Eric-Guo avatar Jun 08 '17 04:06 Eric-Guo

能在本地改一下最新0.8.8的这几行确认一下么?

@Eric-Guo 实测0.8.11是无法在rails5 api下正常显示json返回的结果的。在0.8.11下按上面回复的修改后可以正常显示出json返回的结果的

但是修改之后GET访问 /wechat 是会报错的,错误信息为“undefined local variable or method `wechat_responder' for WechatsController:Class”

LSkipJackie avatar Aug 05 '17 14:08 LSkipJackie

@numbcoder 找到了一个解决方法,在 Rails 5.1.4 + Jbuilder 2.7.0 + wechat 0.8.12 可以正常使用

class ApplicationController < ActionController::API
  include ActionView::Rendering

  def render_to_body(options)
    _render_to_body_with_renderer(options) || super
  end
end

Youngv avatar Dec 21 '17 09:12 Youngv

和 @numbcoder 一样,jbuilder 和 render: json 不能同时用

ifsc01 avatar Aug 19 '19 09:08 ifsc01

今天我也遇到了,直接include 可解,Rails 6.0.1

  class EventsController < ActionController::API
    include ActionView::Rendering
    # Support render json: nil
    def render_to_body(options)
      _render_to_body_with_renderer(options) || super
    end
  end

Eric-Guo avatar Dec 05 '19 12:12 Eric-Guo