Rails 不知道为什么,但感觉醉了

Catherine · 2016年04月12日 · 最后由 catherine 回复于 2016年06月27日 · 2589 次阅读

一个子项目,和主项目类似,用的是 manage 域/user/feedback 这种域以及继承关系。

子项目我就直接在 user 文件夹下建了 feedbacksController 以及相关 view、model,继承关系不会有一点错。 继承关系如下:

app/controllers/user/feedbacks_controller.rb
class User::FeedbacksController < User::ApplicationController
end

app/controllers/user/application_controller.rb
class User::ApplicationController < BasesController
end

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
end

app/controllers/base_controller.rb
class BasesController < PatternsController
end

app/controllers/patterns_controller.rb
class PatternsController < ApplicationController
end

除了 base_controller 有些常用方法,以及 patterscontroller 里的统一模板方法外,/user 下的控制器只定义了继承关系,什么都没有

在 patternscontroller 里定义了统一的 index、show 等方法

诡异的一幕出现了。重启项目,先打开 home_path,然后进入我的 user_feedbacks_path,出错,说@feedbacks为 nil。也就是说完全没有进入 patterscontroller(在 patterscontroller 里的 index 方法里打了断点,报错的时候压根没有进去) 而这时不关闭服务,直接随便找一个文件,在一个没有意义的地方加个没有意义的空格,保存。同样的地址,可以访问了。(就是 pattercontroller 的 index 页面),进入断点了...一切正常了。

但只要重启服务,先访问 home_path,然后再进 user_feedbacks_path,就妥妥的报错。

查过路由没有 user_*_path 被用的情况,除了我的 user_feedbacks_path。
换了个 person 的域指回 user 就完全正常了....

namespace :person, path: 'user' do
  resources :feedbacks do
end

model 下有 user.rb,但也有个 user 文件夹,model/user 下的所有类都可以正常 curd controller 下有 users_controller

应该是这俩存在的原因吧,它的 index show 等方法和页面都可以完全正常使用,只能猜测,不知道怎么定位到问题的根源。虽然解决了问题,但只是解决了问题...

1 楼 已删除

你猜我猜不猜?

额,信息太少

应该是 namespace 的问题,这个问题之前也困扰了我一段时间

ruby 中 classmodule 这两个关键字的含义可以仔细思考一下。 在其他的编程语言中可以简单的理解为定义声明一个类、模块。 但在 ruby 中,你最好理解为声明并打开一个类、模块。

回到你的问题上面来,我猜测你 99% 有一个 model 叫做

class User < ActiveRecord::Base # 声明并打开一个名叫 User 的类
end
class User::FeedbacksController < BasesController
end
# 这个代码等价于
module User #  声明并打开一个名叫 User 的模块
  class FeedbacksController < BasesController # 在里面声明一个FeedbacksController的类
  end
end

说到这里你可能多少理解了一点点,ruby 不能判断到底应该把 User 当做一个 class 还是 module 你可以在 irb 里面试试声明同名 class、module

irb(main):001:0> module User
irb(main):002:1> end
=> nil
irb(main):003:0> class User
irb(main):004:1> end
TypeError: User is not a class
    from (irb):3
    from /usr/bin/irb:12:in `<main>'
irb(main):005:0>

你就会发现打开 User class 失败。

很多语言当中,都有类似的问题,都算是 namespace 命名空间的问题,C++ 有 include 和 namespace,java 有 import 和 package,objective-C 两个不同 SDK 引入了相同的库的时候,也只能改掉其中一个,erlang 同名 module 直接就报错,只能手动把每个 module 加上特殊的前缀。

其实 ruby 中的做法已经足够使用了,一个 require 和 module,尽量不 require 同名类能解决大部分问题了,再加上一个 namespace,基本上不会出现问题。虽然你的 user/application_controller.rb 中没有 require,但是 rails 的 autoload 已经帮你引入了 model 中所有的类,在你访问 user_feedbacks_path 这个时候,正好懒加载了 module User,所以每次重启到这里就报错了。

可以参考下: http://guides.rubyonrails.org/autoloading_and_reloading_constants.html

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