论坛首页 编程语言技术论坛

对于model是全部放在model下面,还是应该分开包来管理的疑问

浏览 10845 次
该帖已经被评为良好帖
作者 正文
   发表时间:2008-03-03  
按模块划分代码时,感觉rails的支持不是很完美。
如lgn21st所说,有时需要了解一些深层的原理,比如module和class在ruby中都是constant等。
module名和model名相同时也可能产生问题,比如有/controllers/admin/account_controller.rb和/models/admin.rb, 在account_controller里使用类似Admin.find(:all)时它会报错: Admin没有find方法。
这是因为在account_controller.rb在定义了Admin::AccountController,即module Admin和其下的class AccountController,而在admin.rb定义了class Admin,两个地方都定义了constant叫Admin,以哪个为准,取决于ruby查找constant的机制,ruby不同版本间也可能有差异,是不是还跟文件加载顺序相关我不清楚,对于这种情况我们用了rails2.0里已经去掉的model :admin声明,保证在controller里能正确加载使用model admin。--而不是直接找到它上层的module而绕过rails自动加载机制的const_missing。
0 请登录后投票
   发表时间:2008-03-03  
我们的controller组织在多层module/目录下,把model全部放在/models下,效果不错。
0 请登录后投票
   发表时间:2008-03-03  
如果model比较多,有100来个,那么全部放到models目录下,估计也是相当的壮观,找起来嘛,呵呵...更加是不用说了.
不过我暂时没有这么多model,所以暂时没有这个烦恼.

多谢大家热烈的讨论.....
0 请登录后投票
   发表时间:2008-03-06  
liusong1111 写道
按模块划分代码时,感觉rails的支持不是很完美。
如lgn21st所说,有时需要了解一些深层的原理,比如module和class在ruby中都是constant等。
module名和model名相同时也可能产生问题,比如有/controllers/admin/account_controller.rb和/models/admin.rb, 在account_controller里使用类似Admin.find(:all)时它会报错: Admin没有find方法。
这是因为在account_controller.rb在定义了Admin::AccountController,即module Admin和其下的class AccountController,而在admin.rb定义了class Admin,两个地方都定义了constant叫Admin,以哪个为准,取决于ruby查找constant的机制,ruby不同版本间也可能有差异,是不是还跟文件加载顺序相关我不清楚,对于这种情况我们用了rails2.0里已经去掉的model :admin声明,保证在controller里能正确加载使用model admin。--而不是直接找到它上层的module而绕过rails自动加载机制的const_missing。

写ruby第一要注意的就是“想尽一切办法避免重名”,不论是类/模块,还是方法/变量。。。
否则有你忙活的时候。
0 请登录后投票
   发表时间:2008-03-06  
除了model,其他的controllers/services/helpers你都可以分层,就像java Package一样的,rails的classloader机制可以让你同一个module下不需require,所以只要分层一样用起来也很方便,这样也可以避免一些同名问题
0 请登录后投票
   发表时间:2008-03-06  
model比较多时可以放在多个目录下,只要在environment.rb下设置一下就可以直接拿过来用了

Rails::Initializer.run do |config|
  config.load_paths += Dir["#{RAILS_ROOT}/app/models/[a-z]*"]
end

[ "app/models" ].each do |path|
  Dir["#{RAILS_ROOT}/#{path}/**/*.rb"].each{|file|
    load file
  }
end
0 请登录后投票
   发表时间:2008-03-06  
pig345 写道
liusong1111 写道
按模块划分代码时,感觉rails的支持不是很完美。
如lgn21st所说,有时需要了解一些深层的原理,比如module和class在ruby中都是constant等。
module名和model名相同时也可能产生问题,比如有/controllers/admin/account_controller.rb和/models/admin.rb, 在account_controller里使用类似Admin.find(:all)时它会报错: Admin没有find方法。
这是因为在account_controller.rb在定义了Admin::AccountController,即module Admin和其下的class AccountController,而在admin.rb定义了class Admin,两个地方都定义了constant叫Admin,以哪个为准,取决于ruby查找constant的机制,ruby不同版本间也可能有差异,是不是还跟文件加载顺序相关我不清楚,对于这种情况我们用了rails2.0里已经去掉的model :admin声明,保证在controller里能正确加载使用model admin。--而不是直接找到它上层的module而绕过rails自动加载机制的const_missing。

写ruby第一要注意的就是“想尽一切办法避免重名”,不论是类/模块,还是方法/变量。。。
否则有你忙活的时候。


我们也在尽力避免重复和二义性情况的出现,能把类、模块、方法、变量的名字起到刻骨的好的程度,就是优秀设计的显著的外在表现,可世事难预料啊,呵呵~
ruby的module用于持有一些独立功能,它有两个职责:mixin和namespace,两者在原理上并没有明显的界限,前者重在功能动态增强,后者重在功能静态隔离,在实际使用中有可能重点使用职责之一。
ajoo老大前面的贴子提出当module作为namespace职责时表达形式不直观,我现在的问题是namespace的名字和类的名字冲突了,在java里package是小写,类名是大写,文件名/路径 与 package/class名字强制保持一致,ruby把namespace(module)和class都作为constant看待,rails重载const_missing实现自动加载,这是两者的不同,对于java来说这种问题就不容易出现。
namespace和class不应该重名吗?
以java的经验看,重名是可以理解的。以ruby实现的角度看,有潜在问题。
我现在也只好记着这个技术约束,注意父模块和同级的类重名的问题~

---
写ruby第一要注意的就是“想尽一切办法避免重名”,--- 我刚刚体会到你这句话的意思,对,深有体会,重名时执行的先后顺序决定最终结果,可能导致诡异的问题,动态性真是个双刃剑。我上面的问题跟这还有些区别:

class A
end

module C
  module A
    class B
      # use class A
    end
  end
end

0 请登录后投票
   发表时间:2008-03-06  
刚接触ruby没多少天,由于之前是用java的,觉得ruby在命名空间似乎处理得不如java那般明确,加上rails隐藏了很多类加载的机制和潜规则,所以如何来合理组织一个代码项目结构似乎成为了ror开发要解决的一大问题。不知道做过项目的同学能不能共享一下经验?
0 请登录后投票
   发表时间:2008-03-06  
rails的自动加载机制源码在active_support的dependencies.rb,Waves框架的创始人说他的更好,抽成了一个叫autocode的gem: http://rubyforge.org/projects/autocode/

本质都是重写const_missing,难点是在重新加载文件之前需要卸载干净(remove_const)以前的const定义,否则在内存中相当于在老的const定义基础上合并了新的定义,会造成一些不可预期的问题 -- 比如重新加载的文件中对类A加了方法a,重定义了方法b,删了方法c,在运行过程中发现a,b都正确了,c居然还存在。由于const的定义本质是在执行过程中动态加入的,可以做到很灵活的添加const,没有机制标记某个const就是对应在哪个文件中创建的,所以需不需要以及如何标记哪些const可以被reload也是问题。rails于是约定了自动加载的类和其文件名/路径的对应关系(ruby语言本身没有这种强性要求)。

autocode的代码比rails清晰多了。
0 请登录后投票
   发表时间:2008-03-07  
如果问题是:
liusong1111 写道

class A
end

module C
  module A
    class B
      # use class A
    end
  end
end



那么,考虑下:

ruby存在的时间比java更久,这么基础的问题(严重点说——缺陷)难道只有咱们碰到过?

或者是ruby社区长久以来对此一直视而不见???这、这ruby还能用么。。。




先放两句大话,呵呵,其实也是最近才找到解决方法,分享下:

class A
  def self.who?
    puts self
  end
end

module C
  module A
    class B
      def self.ask_A
        A.who?
        ::A.who?
      end
    end
    def self.who?
      puts self
    end
  end
end

C::A::B.ask_A


irb里面实验下看看?
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics