Ruby on Rails.未初始化的常量

Nem*_*den 5 ruby ruby-on-rails carrierwave

这很奇怪,但是:

上传器类(app/uploaders):

class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  # ....

  version :thumb, from_version: :preview do
    process resize_to_limit: [Image::THUMB_WIDTH]
  end
Run Code Online (Sandbox Code Playgroud)

图像类(app/models):

class Image < ActiveRecord::Base
  include Rails.application.routes.url_helpers
  mount_uploader :image, ImageUploader

  THUMB_WIDTH = 220
  PREVIEW_WIDTH = 460
  MAX_WIDTH = 960
Run Code Online (Sandbox Code Playgroud)

申请说:

uninitialized constant Image::THUMB_WIDTH

  version :thumb, from_version: :preview do
    process resize_to_limit: [Image::THUMB_WIDTH] #<<<----
  end

  version :preview, from_version: :fullsize do
Run Code Online (Sandbox Code Playgroud)

怎么了?

更新:

阿吉斯指出了原因.

Bounty将在2天内应用此问题的最佳解决方案.我不喜欢代码分离,例如在初始化器中创建一个新类,用于保存Image类的所有常量.这个解决方案很糟糕,因为它带来了不一致和代码碎片.

bbo*_*ozo 9

一般答案

就rails自动加载器而言,你有一个鸡或蛋的情况,在一般意义上解决这个问题的"轨道方式"是重构元代码,以便类名作为字符串值而不是类传递,例如:

belongs_to :manager, class_name: "Employee"
Run Code Online (Sandbox Code Playgroud)

belongs_to希望在所有课程都已加载的时候打电话constantize,class_name这样鸡和鸡蛋的问题就被绕开了"铁路".

什么@Stoic建议实质上是回避的评价这一主题的变化image.rb,在image_uploader.rb加载时间:

model.class.const_get("THUMB_WIDTH")
Run Code Online (Sandbox Code Playgroud)

也可以被表述为:

'Image'.constantize.const_get("THUMB_WIDTH")
Run Code Online (Sandbox Code Playgroud)

结果是一样的,从中可以得出的一般教训是:避免在类加载时代码中使用另一个类名文字,换句话说belongs_to :manager, class_name: "Employee"是好的并且belongs_to :manager, class_name: Employee会很糟糕.

它不漂亮,但它可能是避免这些头痛的最优雅的通​​用方法


问题具体答案

查看问题的一种不同方式是缩略图图标宽度实际上是上传者而不是模型的关注点,并且您实际上看到了一个不恰当的亲密代码气味的边缘情况(http://www.codinghorror. com/blog/2006/05/code-smells.html).

注意那些花费太多时间在一起的课程,或者以不恰当的方式进行交流的课程.课程应该尽可能少地了解彼此.

所以,如果你是这个思想学派(我倾向于这个方向),那么解决方案就是使课程THUMB_WIDTH保持不变,ImageUploader问题就会消失.

无论如何,将模型中的不同域关注点分离出来通常是一个好主意,因为模型会变得臃肿和无法管理 - 您可以将上传器类视为模型的服务类,旨在以相同的方式提取特定的域问题值对象,表单对象等在http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/中处理


计划C将切换config.autoload_pathsapplication.rb和交叉手指的地方:)