【问题标题】:Which association should I use to describe `Types of things' in Ruby on Rails?我应该使用哪个关联来描述 Ruby on Rails 中的“事物类型”?
【发布时间】:2010-02-05 21:37:48
【问题描述】:

我希望能够使用 RoR 关联来描述不同类型的模型。一个例子:

型号:
发帖

图片发布
post_id:整数
网址:字符串

消息发布
post_id:整数
消息:字符串

ImagePost 和 MessagePost 是 Post 的一种。我希望@posts = Post.all 检索这两种类型的帖子并允许我通过@posts.url 或@posts.message 访问它们的属性。

我确定我错过了一些简单的东西,请赐教!

干杯,

本。

【问题讨论】:

    标签: ruby-on-rails associations


    【解决方案1】:

    查看单表继承的概念——基本思想是您将拥有一个具有类型列的单个 Post 表,因此给定的 ImagePost 仍然只是 Post 表中的一行。 Post 表将包含所有可能属性的列,因此它将包含 url 和 message 列。

    那么对应的模型类就会继承自Post:ImagePost

    【讨论】:

    • 我读过关于单表继承的文章,但由于将所有内容存储在一个表中导致的冗余字段而被推迟。然后我继续研究多态关系,但这似乎也不适合。如果这是我的方案的最佳实践,那我将采用。感谢您的帮助!
    【解决方案2】:

    您可以尝试混合模型方法,但设置工作量很大。以性能换取更高效的数据库存储,这有点杂乱无章。

    这个想法是您使用 STI 来处理所有常见的 Post 字段,并将每个子类的唯一字段委托给另一个表并立即加载该关联。

    基本 Post 类可能如下所示。请注意,class_eval 可以抽象为一个模块,该模块被包含并扩展为子类。

    #columns: id:integer, timestamps, user_id:integer, 
    #  topic_id:integer, type:string
    class Post < ActiveRecord::Base
      # common methods/validations/associations
      belongs_to :user
      belongs_to :topic 
    
      def self.relate_to_detail
        class_eval <<-"EOF"
          has_one :detail, :class_name => "#{self.name}Detail"
          accepts_nested_attributes_for :detail
    
          default_scope :include => :detail
    
          def method_missing(method, *args)
            build_detail if detail.nil?
            if detail && detail.respond_to?(method, true)
              detail.send(method, *args)
            else 
              super(method, *args)
            end
          end
    
          def respond_to?( method, include_private = false)
            build_detail if detail.nil?
            super(method, include_private) || 
              detail.respond_to?(method, include_private)
          end
        EOF
      end
    end
    

    然后你需要为每种类型定义子类和细节类。

    #uses posts table
    class ImagePost < Post
      relate_to_detail
    end
    
    #columns: id, image_post_id, url:string, height:integer, :width:integer
    class ImagePostDetail < ActiveRecord::Base
      belongs_to :image_post
    end
    
    #uses posts table
    class MessagePost < Post
      relate_to_detail
    end
    
    #columns: id, message_post_id, message:string
    class MessagePostDetail < ActiveRecord::Base
      belongs_to :image_post
    end
    

    现在我们可以这样做了:

    @user.message_posts.create(:message => "This is a message")
    @image_post.url
    

    这将创建一个新的MessagePost,其中user_id、timestamps、post_id、post_type都存储在posts表中,而消息存储在MessagePostDetails表中并分别返回一个ImagePost的url。

    新的method_missing 和respond_to?定义具有隐藏除法的魔力。

    @Post.all 现在将列出所有类型的帖子。唯一的缺点是获取帖子时不会显示详细信息字段。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多