Rails:构建涉及多态关联和STI的查询 [英] Rails: Structuring a query involving a polymorphic association and STI

本文介绍了Rails:构建涉及多态关联和STI的查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试查找有关照片的10条最新评论,以便将其集成到Rails 3.0.3应用程序的活动供稿中.

我有一个照片模型,该模型使用单表继承从上传模型继承:

class Upload < ActiveRecord::Base
    ...
end

class Photo < Upload
    has_many :comments, :as => :commentable
    ...
end

注释模型中描述了多态关联可注释:

class Comment < ActiveRecord::Base
    belongs_to :commentable, :polymorphic => true
end

到目前为止一切都很好,对吗?当我尝试构造查询时,问题就来了.经过一番尝试和错误之后,我想到了Photo模型中的以下代码:

def self.latest_comments(count = 10)
    Comment.where(:commentable_type => "Upload")\
       .joins("INNER JOIN uploads ON comments.commentable_id = uploads.id")\
       .where("uploads.type" => "Photo").order("comments.created_at DESC").limit(count)
end

此代码可在使用SQLite的开发计算机上运行,​​但是我必须进行一些更改才能使其在使用PostgreSQL的生产服务器上运行.上面的查询化身尚未在生产服务器上进行过测试,但是我一直在寻找一种结构化查询的更简洁的方法,因为上面的内容感觉不太稳健,也似乎不太"Railsy". /p>

我想说的是

Comment.joins(:commentable => :photo)

...但是这引发了一个异常,大概是因为Rails不知道如何进行连接:

ActiveRecord :: EagerLoadPolymorphicError:无法急切加载多态关联:commentable

我遇到了关于StackOverflow的帖子,其中描述了查询多态关联的另一种方法.我根据这篇文章提出了以下代码:

Comment.find_all_by_commentable_type("Upload", :include => :commentable,
        :order => "created_at DESC", :limit => 10)

但是,这不适用于STI:由于Photo是从Upload继承的,因此我无法直接获取与照片有关的注释-仅从继承自Upload的所有类的注释.

我看过很多其他有关多态性或STI的文章,但没有一个以我所寻找的方式将两者结合在一起.我可以混淆初始查询,但是有人对构建涉及多态性 STI的查询的替代方法有任何想法吗?

编辑:我在这里找到了另一个问题作为我的.不幸的是,最重要的答案没有提供我想要的解决方案.如果将其应用于我的问题,我将把has_many :comments关联从Photo模型移动到Upload模型,并向Comment类添加一些代码,以确定commentable的正确类.这是不理想的,因为它破坏了建模,因为Upload的任何子类都将带有注释.必须有更好的方法...?

解决方案

您正在提供与Upload类上的注释的关联.从上载继承的照片将通过继承而具有这种关联.由于注释方法在上载实例和照片实例上均可用,因此您可以编写以下方法来检索注释:

# app/models/upload.rb

def latest_comments(count=10)
  self.comments.order("created_at DESC").limit(count)
end

在使用Upload实例时,它将使用"Upload"类型加入注释表,在使用该类的实例时,将使用"Photo"类型加入注释表.在进行注释关联时,Rails将使用类名称自动处理到注释表的联接.

I'm trying to find the 10 most recent comments on photos so I can integrate them into an activity feed on my Rails 3.0.3 application.

I've got a Photo model, which inherits from an Upload model using single table inheritance:

class Upload < ActiveRecord::Base
    ...
end

class Photo < Upload
    has_many :comments, :as => :commentable
    ...
end

The polymorphic association commentable is described in the Comment model:

class Comment < ActiveRecord::Base
    belongs_to :commentable, :polymorphic => true
end

So far so good, right? The problem comes when I try to construct a query. After some trial and error, I came up with this code that sits in the Photo model:

def self.latest_comments(count = 10)
    Comment.where(:commentable_type => "Upload")\
       .joins("INNER JOIN uploads ON comments.commentable_id = uploads.id")\
       .where("uploads.type" => "Photo").order("comments.created_at DESC").limit(count)
end

This code works on my development machine with SQLite, but I've had to make some changes to get it to work on the production server using PostgreSQL. The above incarnation of the query hasn't been tested on the production server yet, but I was looking for a cleaner way of structuring the query, as the above doesn't feel very robust, nor does it seem very 'Railsy'.

What I'd like is to be able to say is

Comment.joins(:commentable => :photo)

...but this raises an exception, presumably because Rails doesn't know how to do the join:

ActiveRecord::EagerLoadPolymorphicError: Can not eagerly load the polymorphic association :commentable

I came upon a post on StackOverflow that described a different way of querying a polymorphic association. I was able to come up with the following code based upon this post:

Comment.find_all_by_commentable_type("Upload", :include => :commentable,
        :order => "created_at DESC", :limit => 10)

However, this doesn't work for STI: since Photo is inheriting from Upload, I can't directly fetch the comments pertaining to photos - only the comments for all classes inheriting from Upload.

I've looked at a fair number of other posts relating to either polymorphism or STI, but none combine the two in the way I'm looking for. I could just muddle around with the initial query, but does anyone have any thoughts on alternative ways to structure a query involving polymorphism and STI?

Edit: I found another question on here along the same lines as mine. Unfortunately, the top answer didn't provide the solution I'm looking for. If I were to apply it to my problem I'd be moving the has_many :comments association from the Photo model to the Upload model, and adding some code to the Comment class to determine the correct class of commentable. This isn't ideal as it breaks the modelling in that any subclass of Upload will have comments. There must be a better way...?

解决方案

You are providing the association to comments on the Upload class. Photo, which is inheriting from Upload will have this association through inheritance. Since the comments method is available on both the Upload instance, and on the Photo instance, you can write the following method to retrieve the comments:

# app/models/upload.rb

def latest_comments(count=10)
  self.comments.order("created_at DESC").limit(count)
end

This will join to the comments table using the type "Upload" when working with an instance of Upload, and it will join using the type "Photo" when using working with instances of that class. Rails will automatically handle the join to the comments table using the class name when going through the comments association.

这篇关于Rails:构建涉及多态关联和STI的查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆