2

考虑这些模型:

class First < ActiveRecord::Base
  has_many :tags
  has_many :thirds, :through => :tags
end

class Second < ActiveRecord::Base
end

class Third < Second
  has_many :tags
  has_many :firsts, :through => :tags
end

class Tag < ActiveRecord::Base
  belongs_to :first
  belongs_to :third
end

换句话说,我们有一个 has_many :through 'tag-style' 关系,但是其中一个模型(第三个)是从另一个(第二个)继承的 STI。

假设我想做一个连接来查看所有第三个实例以获得第一的某些值:

@thirds = Third.joins(:firsts).where("first.id = 2")

这将按预期工作;生成的 sql(通过 to_sql)是:

SELECT `seconds`.* FROM `seconds`
INNER JOIN `tags` ON `seconds`.`id` = `tags`.`third_id`
INNER JOIN `firsts` ON `firsts`.`id` = `tags`.`first_id`
WHERE `seconds`.`type` = 'Third' AND (first.id = 1)

这在另一个方向不起作用:

@firsts = First.joins(:thirds).where("second.id = 2")

生成的 SQL 为:

SELECT `firsts`.* FROM `firsts` 
INNER JOIN `tags` ON `firsts`.`id` = `tags`.`first_id` 
INNER JOIN `seconds` ON `seconds`.`type` = 'Third'
WHERE (second.id = 2)

这会导致标签重复,因为 :seconds 没有像上面的第一种情况那样与标签表正确连接(参见每种情况下的第三行 sql 语句)。所有带标签的第一个都将显示在结果表中,WHERE 子句完全无效。

如果需要指定其他内容,我还没有遇到过。如果有人知道如何强制它工作,请告诉我。否则,我假设这是 Rails 中的一个错误。哦,请不要建议我使用将被弃用的旧 model.find() 方法。

更新:

https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6608-generated-sql-for-has_many-through-relation-wrong-when-used-with-sti

因此,根据确认这是一个错误的人所说,“如果你在基类中定义关联,它会按预期工作。” 有谁知道这意味着什么/如何做到这一点?

4

1 回答 1

1

您的查询几乎没有变化:

@thirds = Third.joins(:firsts).where(:firsts => {:id => 2})
@firsts = First.joins(:thirds).where(:thirds => {:id => 2})

我认为你应该尝试在你的 STI 模型中添加一些 coomon 的东西:

class Third < Second
  has_many :tags
  has_many :firsts, :through => :tags
  def self.model_name
    name = "seconds"
    name.instance_eval do
      def plural;   pluralize;   end
      def singular; singularize; end
      def i18n_key; singularize; end
      def human(*args); singularize; end
    end
    return name
  end
end

并查看这篇精彩的阅读http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html

或者您可以在该链接中阅读,您可以使用这种看起来不太干净的方法

def self.inherited(child)
  child.instance_eval do
    def model_name
      Second.model_name
    end
  end
  super
end
于 2011-03-23T15:05:57.377 回答