具有has_many和belongs_to的Rails查询出现意外结果

时间:2019-01-25 03:19:17

标签: ruby-on-rails ruby ruby-on-rails-5

我正在构建一个Rails应用,并且有一个名为Item的模型。它属于一个Type,并通过ItemType具有has_many Types。

通过其has_many Types关联查询项目时,我期望不会有任何结果,但是当它们属于该类型时,我会找回它们。

# models/item.rb
class Item < ApplicationRecord
  has_many :item_types
  has_many :types, through: :item_types
  belongs_to :type, inverse_of: :items
end

# models/type.rb
class Type < ApplicationRecord
  has_many :items, inverse_of: :item_type, dependent: :nullify
end

# models/itemtype.rb
class ItemType < ApplicationRecord
  belongs_to :item
  belongs_to :type
end

示例(预期行为):

food = Type.create
pizza = Item.create(type: food)

irb> pizza.type
food

irb> pizza.types
[]

但是,当我查询具有关联项目类型的项目并且期望没有结果时,即使没有ItemType对象,我也要取回我的项目。

irb> Item.where(type: food)
pizza
irb> Item.where(types: food)
pizza

(尽管Pizza.types返回[]的事实仍然返回了披萨)

我不确定幕后发生的事情,但是我发现这是意外的行为。为什么会发生这种情况,如何获取Item.where(types: food)查询,但不返回结果?

2 个答案:

答案 0 :(得分:0)

您的模型不太正确;如果您希望它们与数据库一起使用,则需要从ApplicationRecord继承。您应该使用生成器来生成模型。

rails g model Item name:string
rails g model Type name:string
rails g model ItemType item:references type:references

然后,修改模型,使其外观如下:

class Item < ApplicationRecord
  has_many :item_types
  has_many :types, through: :item_types
end

class Type < ApplicationRecord
  has_many :item_types
  has_many :items, through: :item_types
end

class ItemType < ApplicationRecord
  belongs_to :item
  belongs_to :type
end

您的语法适用于伪代码,但是下面的代码应该可以正常工作

carbs = Type.create(name: 'Carbs')
pizza = Item.create(name: 'Pizza')
carbs.items << pizza

您还可以动态创建项目,如下所示:

carbs.items.create(name: 'Milkshake')

然后您可以访问以下内容:

carbs.items.first.name #=> 'Pizza'
pizza.types.map(&:name) #=> ['Carbs']

您需要查看association basics documentation的其他功能。

答案 1 :(得分:0)

我已经找到了解决此问题的可行解决方案,因此将其放在此处以供将来的读者使用。

问题在于,无论是按Item.where(type: food)还是Item.where(types: food)类型按类型或类型查询项目都是模棱两可的,并且似乎使用belongs_to :type引用了Item模型中定义的belongs_to关系

要解决此问题,要按项类型查询项,您可以先使用includes(:item_types)联接表,然后再查询其类型属于所需实例的项类型。

为我提供理想结果的查询结果是Item.includes(:item_types).where(item_type: {type: food})