Rails 4:与范围的多个连接

时间:2014-07-04 22:15:12

标签: ruby-on-rails scope many-to-many has-many-through eager-loading

以下ERD包括问题中涉及的类。

ER Diagram

以下是3个主要类(监控,链接和故事)的代码。

class Monitoring < ActiveRecord::Base
  belongs_to :company

  has_many :keywords, through: :monitoring_keywords
  has_many :monitoring_unread_keywords, -> { order("count asc") } # database view
  has_many :monitoring_keywords, dependent: :destroy
  has_many :stories, through: :links
  has_many :links
end

class Link < ActiveRecord::Base
  belongs_to :monitoring
  belongs_to :story

  has_many :keyword_links
  has_many :keywords, through: :keyword_links, dependent: :destroy

  scope :unreads, -> { where(viewed: false) }
  scope :rateds, -> { where("rating is not null") }
  scope :sents, -> { where(sent: true) }
  scope :discardeds, -> { where(discarded: true) }
  scope :clickeds, -> { where(clicked: true) }
end

class Story < ActiveRecord::Base
  has_many :keyword_links, through: :links
  has_many :keywords, through: :keyword_links
  has_many :links

  belongs_to :source
end

我想要的是获得所有监控,包括关键字和今天的故事。以下查询返回我想要的内容,但包含所有故事。

# company_id is a column in monitorings
@monitorings = Monitoring.joins(:stories).includes([{ stories: [:source] }, :keywords]).where(company_id: current_company.id)

Response

Response (original size)

我不知道如何只获得今天的故事。如果我添加到where方法stories: { created_at: Date.today.beginning_of_day..Date.today.end_of_day },rails仍会获取所有故事,但只能获得当天至少有一个故事的监控。

我还尝试在has_many :stories, -> { where(created_at: Date.today.beginning_of_day..Date.today.end_of_day) }, class_name: "Story", foreign_key: "story_id"之类的监控中添加网络关系,但我无法使其发挥作用。

缺少信息:监控与公司有n-1关系,监控中的company_id字段用于过滤结果。

6 个答案:

答案 0 :(得分:1)

如果您想使用预先加载(includes)并限制结果,Rails Docs建议您创建新关联。在这种情况下,您需要在link.rb

中创建新关联
has_many :todays_stories, -> { where(created_at: Date.today.beginning_of_day..Date.today.end_of_day)}, class_name: "Story"

然后您可以在monitoring.rb

中添加新关系
has_many :todays_stories, through: :links

然后你可以执行以下查询(我调整它以使用我在多租户环境中使用的格式)

@monitorings = current_company.monitorings.includes(:keywords, todays_stories: :source)

以下代码应返回您要查找的结果

@monitorings.first.todays_stories

答案 1 :(得分:1)

尝试

@monitorings = Monitoring.joins(:stories).includes([{ stories: [:source] }, :keywords]).where(company_id: current_company.id).where('stories.created_at > ? AND stories.created_at < ?', Date.today.beginning_of_day, Date.tomorrow.beginning_of_day)

答案 2 :(得分:0)

尝试:

@monitorings = Monitoring.joins(:stories).
               includes([{ stories: [:source] }, :keywords]).
               where(company_id: current_company.id).
               where('stories.created_at > ?', Date.today.beginning_of_day)

我有时也做了一些额外的关联,它是我想要的范围。

class Monitoring < ActiveRecord::Base
  belongs_to :company

  has_many :keywords, through: :monitoring_keywords
  has_many :monitoring_unread_keywords, -> { order("count asc") } # database view
  has_many :monitoring_keywords, dependent: :destroy
  has_many :stories, through: :links
  has_many :new_stories, -> { where(created_at: Date.today.beginning_of_day..Date.today.end_of_day)}, through: :links
  has_many :links
end

然后你可以这样做:

@monitorings = Monitoring.joins(:new_stories).
           includes([{ stories: [:source] }, :keywords]).
           where(company_id: current_company.id)

由于上面的答案,我遇到this article关于合并的问题,虽然我还没有测试过,但它可能完全符合您的要求。

答案 3 :(得分:0)

您可以在故事课中使用范围 例如,如果您想要故事,那么它们只会在今天创建 你可以写

default_scope - &gt; {
  where(&#39; created_at&gt;?&#39;,Time.now.beginning_of_day)
}

答案 4 :(得分:0)

看起来Rails正在进行监控和故事的内部联接,这意味着您无法获得任何没有相关故事的监控记录。

解决此问题的一种方法是为joins指定一个自定义子句,但根据Rails Guides,如果您使用includes where条件,它会自动发生在连接表上(这是你想要做的事情)。

tl; dr :尝试从查询中删除joins来电:

@monitorings = Monitoring.includes([{ stories: [:source] }, :keywords]).where(company_id: current_company.id, stories: { created_at: Date.today.beginning_of_day..Date.today.end_of_day })

答案 5 :(得分:0)

我认为您应该手动编写连接查询。尝试类似的东西:

s = Monitoring.joins(
"inner join links on links.monitoring_id = monitoring.id" +
"inner join stroies on stroies.id = links.story_id"
).where("stroies.created_at = '?'", target_date).includes(:keywords)

对不起,如果我理解错了。我也可能与单数/复数不匹配