1

我确信这与我对 Ruby 内部结构缺乏了解有关,但这里有:

本质上,我希望能够通过简单地has_attachments_folder "videos"在模型顶部附近调用来在我的资产文件夹中设置一个“附件目录”。不要担心这个方法的目的是什么,我有它的一部分工作。下面的示例用法。

视频.rb

class Video < ActiveRecord::Base
    has_attachment_assets_folder "videos"
end

电子邮件.rb

class Email < ActiveRecord::Base
    has_attachment_assets_folder "attachments/email"
end

activerecord_base.rb

def self.has_attachment_assets_folder(physical_path, arguments={})
    ActiveRecord::Base.send :define_method, :global_assets_path do |args={}|
        # Default to using the absolute system file path unless the argument
        # :asset_path => true is supplied
        p = "#{ Rails.root }/app/assets/#{ physical_path }"
        if args[:asset_path]
            p = "/assets/#{ physical_path.include?("/") ? physical_path.partition("/")[2..-1].join("/") : physical_path }"
        end
        p.squeeze!("/")
        logger.info "Defining global_assets_path...class name: #{ self.class.name }, physical_path: #{ physical_path }, p: #{ p }"
        p
    end
end

所以本质上,方法 global_assets_path 应该返回由调用指定的附件目录的完整或相对路径has_attachment_assets_folder

has_attachment_assets_folder "videos", :asset_path => true= "/assets/videos" has_attachment_assets_folder "attachments/email", :asset_path => true="/assets/attachments/email"

问题是,如果我在 Rails 应用程序的常规上下文中使用它(一次访问一个模型),它就可以正常工作。但是,我正在运行一项重大迁移,这需要我在迁移文件中一次使用多个模型。似乎每个模型都共享该方法global_assets_path,因为发生了以下情况:

示例 1

Email.all.each do |e|
    puts e.global_assets_path(:asset_path => true) # Correct output of "/assets/attachments/email"
end
Video.all.each do |v|
    puts v.global_assets_path(:asset_path => true) # Correct output of "/assets/video"
end

示例 2

test = Video.pluck(:category)
Email.all.each do |e|
    puts e.global_assets_path(:asset_path => true) # Correct output of "/assets/attachments/email"
end
Video.all.each do |v|
    puts v.global_assets_path(:asset_path => true) # Incorrect output of "/assets/attachments/email" because the Video model was instantiated for the first time on the 1st line.
end
4

1 回答 1

0

你叫define_method错了。这个:

ActiveRecord::Base.send :define_method, :global_assets_path

正在发送define_method到,ActiveRecord::Base以便将确切的global_assets_path方法添加到ActiveRecord::Base. 当你这样说时:

class Email < ActiveRecord::Base
    has_attachment_assets_folder "attachments/email"
end

您想将您的global_assets_path方法添加到Email,而不是ActiveRecord::Base. selfEmail在该has_attachment_assets_folder电话中,因此您想说:

def self.has_attachment_assets_folder(physical_path, arguments = {})
    define_method :global_assets_path do |args={}|
        ...
    end
end

global_assets_pathselfActiveRecord::Base子类)上定义并且不理会ActiveRecord::Base它自己。

于 2013-10-11T06:31:45.443 回答