简体   繁体   English

ActiveRecord has_many通过多态has_many

[英]ActiveRecord has_many through polymorphic has_many

It seems like rails still not support this type of relation and throws ActiveRecord::HasManyThroughAssociationPolymorphicThroughError error. 看起来rails仍然不支持这种类型的关系并抛出ActiveRecord :: HasManyThroughAssociationPolymorphicThroughError错误。

What can I do to implement this kind of relation? 我该怎么做才能实现这种关系?

I have following associations: 我有以下关联:

Users 1..n Articles
Categories n..n Articles
Projects 1..n Articles

And here is Subscription model 这是订阅模型

Subscription 1..1 User
Subscription 1..1 Target (polymorphic (Article, Category or User))

And I need to select articles through Subscription#target#article according to user#subscriptions. 我需要根据用户#订阅通过Subscription#target#article选择文章。

I have no idea hot to implement this 我不知道如何实现这一点

Ideally I want to get instance of Association class 理想情况下,我想获得Association类的实例

UPDATE 1 更新1

Here is little example 这是一个小例子

Let say user_1 has 4 Subscription records: 假设user_1有4个订阅记录:

s1 = (user_id: 1, target_id: 3, target_type: 'User')
s2 = (user_id: 1, target_id: 2, target_type: 'Category')
s3 = (user_id: 1, target_id: 3, target_type: 'Project')
s4 = (user_id: 1, target_id: 8, target_type: 'Project')

I need method User#feed_articles, that fetches all articles, that belong to any of target, I subscribed. 我需要方法User#feed_articles,它获取属于任何目标的所有文章,我订阅了。

user_1.feed_articles.order(created_at: :desc).limit(10) 

UPDATE 2 更新2

I separate articles sources by type in User model: 我在User模型中按类型分隔文章来源:

  has_many :out_subscriptions, class_name: 'Subscription'

  has_many :followes_users, through: :out_subscriptions, source: :target, source_type: 'User'
  has_many :followes_categories, through: :out_subscriptions, source: :target, source_type: 'Category'
  has_many :followes_projects, through: :out_subscriptions, source: :target, source_type: 'Project'

  has_many :feed_user_articles, class_name: 'Article', through: :followes_users, source: :articles
  has_many :feed_category_articles, class_name: 'Article', through: :followes_categories, source: :articles
  has_many :feed_project_articles, class_name: 'Article', through: :followes_projects, source: :articles

But how can I merge feed_user_articles with feed_category_articles and feed_project_articles without loss of perfomance 但是如何在不损失性能的情况下将feed_user_articles与feed_category_articles和feed_project_articles合并

UPDATE 3.1 更新3.1

The only way I found is to use raw SQL join query. 我发现的唯一方法是使用原始SQL连接查询。 Looks like it works fine, but I'm not sure. 看起来它工作正常,但我不确定。

  def feed_articles
    join_clause = <<JOIN
inner join users on articles.user_id = users.id
inner join articles_categories on articles_categories.article_id = articles.id
inner join categories on categories.id = articles_categories.category_id
inner join subscriptions on
    (subscriptions.target_id = users.id and subscriptions.target_type = 'User') or
    (subscriptions.target_id = categories.id and subscriptions.target_type = 'Category')
JOIN

    Article.joins(join_clause).where('subscriptions.user_id' => id).distinct
  end

(This is just for Users and Categories) (这仅适用于用户和类别)

It supports scopes and other features. 它支持范围和其他功能。 The only thing interests me: does this query lead to some undesirable effect? 唯一让我感兴趣的是:这个查询会导致一些不良影响吗?

I think that from DB performance prospective using UNION ALL multiquery will be more efficient than using polymorphic multijoin. 我认为从DB性能前瞻性使用UNION ALL multiquery将比使用多态multijoin更有效。 Also it will be more readable. 它也会更具可读性。 I tried to write an Arel query as example but it does not play nice (I failed to make order by clause work properly) so I think you have to put it via raw SQL. 我尝试编写一个Arel查询作为示例,但它不能很好(我没有使order by子句正常工作)所以我认为你必须通过原始SQL。 You can use SQL template apart from ORDER BY clause for drying it up. 除了ORDER BY子句之外,您还可以使用SQL模板将其烘干。

You are correct that Rails doesn't support has_many :through w/ polymorphic associations. 你是正确的Rails不支持has_many:通过w /多态关联。 You could mimic this behavior by defining an instance method on your User class. 您可以通过在User类上定义实例方法来模仿此行为。 That would look something like this: 这看起来像这样:

def articles
  Article.
    joins("join subscriptions on subscriptions.target_id = articles.id and subscriptions.target_type = 'Article'").
    joins("join users on users.id = subscriptions.user_id")
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM