【问题标题】:has_many :through association through two different associationshas_many :通过关联通过两个不同的关联
【发布时间】:2010-02-26 19:22:38
【问题描述】:

我有四个模型类:

class Group < ActiveRecord::Base
  has_many :projects
  has_many :personal_blogs
end

class Project < ActiveRecord::Base
  has_many :events, :as => :event_producer
end

class PersonalBlog < ActiveRecord::Base
  has_many :events, :as => :event_producer
end

class Event < ActiveRecord::Base
  belongs_to :event_producer, :polymorphic => true
end

我想查找特定组的所有事件。我认为这是一个 has_many :through 关联,但是如何在 Group 上指定一个 has_many 以查找组的项目 personal_blogs 中的所有事件?当然,我可以指定两个关联并连接结果,但随后我必须在 Ruby 中重新排序、限制、条件等,这可能是许多事件的性能噩梦。我想在 ActiveRecord 中这样做以避免这样的噩梦。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    您可以在 Group 类中定义一个方法,如下所示:

    class Group < ActiveRecord::Base
      has_many :projects
      has_many :personal_blogs
    
      def events
        Event.find(:all, :conditions => ['(type = ? AND event_producer_id IN (?)) OR (type = ? AND event_producer IN (?))', 'project', project_ids, 'personal_blog', personal_blog_ids])
      end
    end
    

    如果您不喜欢上一个 SQL,则始终可以使用单表继承。此解决方案取决于您的 classes attributes and behavior,但允许您使用“has_many through”关联。

    【讨论】:

    • 这实际上对我不起作用,因为我需要将搜索限制在特定的组中。对组的引用在连接中是多态的,这使得 SQL 变得相当复杂。
    • 这个其实是被Group限制的。请注意,我使用的“project_ids”和“personal_blog_ids”集合已经过滤掉了不属于实际组的项目和personal_blogs。
    【解决方案2】:

    为什么不直接做:

    class Group < ActiveRecord::Base
      has_many :projects
      has_many :personal_blogs
    
      def all_events
        projects.events + personal_blogs.events
      end
    end
    

    【讨论】:

    • "我当然可以指定两个关联并将结果连接起来,但是我必须在 Ruby 中重新排序、限制、条件等,这可能是许多人的性能噩梦事件。我想在 ActiveRecord 中执行此操作以避免这样的噩梦。"
    【解决方案3】:

    如果您需要一个可以预加载的关联,您可以指定一个自定义“来自”查询,其中包含事件的组 ID。

    class Group < ActiveRecord::Base
      has_many :projects
      has_many :personal_blogs
      has_many :events, -> {from(<<~SQL)}
        (
          SELECT DISTINCT e.*, g.id as group_id
          FROM events e
            LEFT JOIN projects p ON p.event_id = e.id
            LEFT JOIN personal_blogs pb ON pb.event_id = e.id
            INNER JOIN groups g ON g.id IN (p.group_id, pb.group_id)
        ) as events
      SQL
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-27
      • 1970-01-01
      相关资源
      最近更新 更多