Homeland 建议加一个读源码节点,好么?我先提个问题

chenge · 2014年05月10日 · 最后由 chairy11 回复于 2014年05月10日 · 3076 次阅读

如果社区能形成读源码的风气,相信对提高是大有好处的。

我昨天带着对下面代码的 respond_to 的疑问,参观(只能惭愧地这么说,实在看不大懂,感觉参观下也好)了一下 3.2 的 actionpack,没记错吧,我总是记不住那几个 active、action 模块。里面有个 mime_responds 文件,其中有两个 respond_to。猜测是 mixin 到 controller。

源码宫殿里陈列着各种奇怪的代码,散发出一些神秘的气息。元编程的技巧随处可见。不得不佩服老外能琢磨。


def index
  @people = Person.all

  respond_to do |format|
    format.html
    format.xml { render xml: @people }
  end
end

#mime_responds.rb

    def respond_to(*mimes, &block)
      raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?

      if collector = retrieve_collector_from_mimes(mimes, &block)
        response = collector.response
        response ? response.call : default_render({})
      end
    end

相信很多人会和我一样,不是很理解这个写法,现在我基本是理解了,format 的调用估计是做个设置。

能否请高手对照源码解释下,两个 respond_to 是如何起作用的。

还想有一个设计相关的节点,页面设计、数据库设计等

没看过源码,乱猜一下。format 是请求的对象,html,xml 是实例方法 (或干脆是 method_missing),有一个实例变量 is_collected,一个实例方法来判断调用的格式,不是当前格式或 is_collected 就退掉。2 层的 block 啊。

挺好的建议。👍

两个respond_to是不一样的,一个是 class 方法,和respond_with配合起作用,respond_to 要先定义一些要相应地 mine 类型,并放在mimes_for_respond_to中,等到 action 里调用 respond_with 的时候再做处理。

而那个实例方法,就是你代码里的那种,则是先用要相应地 mine 类型和 block 构造一个内部类 Collector https://github.com/rails/rails/blob/bfc34fc0050ce61650701676dd45553aa82214c0/actionpack/lib/action_controller/metal/mime_responds.rb#L466 ,之后就在 collector 的 context 里调用 block,由 collector 来处理响应了,所以可以仔细看一下 Collector 类的代码。

而其实 respond_with 也可以像实例方法 respond_to 那样 block 调用,也是类似的,只不过多了一个 mine 的查找 https://github.com/rails/rails/blob/bfc34fc0050ce61650701676dd45553aa82214c0/actionpack/lib/action_controller/metal/mime_responds.rb#L431

(只能当抛砖引玉了)

#7 楼 @alsotang 应该问题不大吧。Class.new 不会冲突。 #5 楼 @Tony612 #6 楼 @zgm

#8 楼 @chenge

  1. 首先 new 是一个关键字,说不定以后 ruby 心情一好,用到的地方都统一给个 deprecated warning
  2. 如果 Class 里本来就有一个 new 方法呢?那这个 new 可能是变量也可能是调用对吧?

#9 楼 @alsotang 不会,实际上是对应的 new= 方法。这个一般不会用的。

#10 楼 @chenge 初始化的时候用的是 new= 这个方法 之后使用 new['name'] 的时候,就到我说的那个困惑了

#11 楼 @alsotang 没明白你的意思,new['name'] 不还是局部变量么

我这边在 3.2 里 用表单 remote:true 提交,返回的东西这样设置

format.js 
format.json json:@obj

最终不会走 format.js,也就是 action.js.erb 只会执行 json 里的东西,返回一个 json 对象,除非我写成 `format.js text: "javascript balabala'" 测代码的时候写了中文,发现只有双引号才能 alert = =

怀疑是路由没有指定 (.format),于是我加上了 xxxx_path(format: 'js') 结果还是一样

匪夷所思

#13 楼 @palytoxin 大哥你在这里回帖是在干嘛。。。

你先在你的 format.js 里面显式 render 一下 action.js.erb。如果成功的话,就看看是不是你没有遵循某些命名规定,致使 rails 不知道你要输出的是 action.js.erb。

检查:你的 controller 和 method 的方法,以及 action.js.erb 放的位置有没有遵照约定。

#14 楼 @alsotang 囧 不是在讨论 respond_to 的读源码问题么= = 我只是提个问题,有空去翻下源码

这个问题的话, format.json json:@obj 我把这行删掉就没问题了 format.js 就会生效 也就是说,只要没有 format.json, rails 是知道我要输出的是 action.js.erb( 噢,这个 action 是个指代,其实遇到问题的是 create.js.erb

检查:你的 controller 和 method 的方法,以及 action.js.erb 放的位置有没有遵照约定。 这是必须的,是没有问题的 题外:上次给人修 bug 遇到一个问题,各种路径都对,一直报 404,调了一个上午 最后发现是文件名不知道为什么在前面多了一个空格本来是'_partial.html.erb' ==> ' _partial.html.erb'

windows 的资源管理器还没办法重命名,说文件已存在。 不信试试在 cmd 下 rename foo.txt " foo.txt",恶心死。。。

#15 楼 @palytoxin 看看你的 remote: true 那个表单发出去的 request 的 accept 里面声明要接受的是什么 content-type

源码?是 C 的,还是 C++ 的,或是 ruby 的。

我跑题了,还是上面跑题了。

能读 C++ 源码的有几个。不读能深入理解元编程吗。

为什么有本书叫 python 源码剖析,而没有 ruby 的。

#17 楼 @zhouchongzxc 国外是有的,只是没翻译。不是有 Ruby 显微镜这本书么。 从实用来说,主要是 rails 的源码。 当然可以包括一切值得学习探讨的代码。

def iframe_handler @iframe_handler ||= DashboardIFrameHandler.new(@application_interaction_timeout) end

想知道这个 ||= 是做什么用的啊?谢谢各位!

#20 楼 @diorbrand 这个是说:如果那个 handler 是 nil,就执行 new。反之如果不是 nil,就保持不变。

||是或运算,x ||= y, 相当于 x = x || y

#3 楼 @Tony612 谢谢提供的思路。看似简单其实还很复杂,还得慢慢来。 我很喜欢你的博客风格,简洁实用。

#22 楼 @chenge 是的,大概可以看懂,但还是有些地方需要琢磨。后边的 Collector 类我也还没仔细看。 博客其实就是自己写的样式,想简单并能突出主要的内容。

#23 楼 @Tony612

应该是这样写了。这个代码的可读性明显好些。

respond_to :html, :xml

def create
  @user = User.new(params[:user])
  flash[:notice] = 'User was successfully created.' if @user.save
  respond_with(@user)
end

#24 楼 @chenge 对,这其实是 rails3 的写法。。不过好像好多人还保留着之前的写法

各种贴见到的好代码,就像我会收集看到的好文章好句子一样么?好提议!

需要 登录 后方可回复, 如果你还没有账号请 注册新账号