ruby 如何取消查询的范围,但保留has_many关系

acruukt9  于 2022-11-04  发布在  Ruby
关注(0)|答案(1)|浏览(154)

如何“取消”查询的范围,但保留has_many关系?
我有两个模型,每个模型都有default_scopes,我也用不同的scopes进行查询(visibilityactive等)。

class Shop
    has_many :products
    scope :active, -> { where(active: true, visible: true) }
end

class Product
  belongs_to :shop
  default_scope { where(:visible => true, active: true) }
end

active_shop = Shop.create(name: "active",
                          active: true, 
                          visible: true)

inactive_shop = Shop.create(name: "inactive",
                            active: false,
                            visible: false)

active_shop.products.create!(name "active product", 
                            visible: true,
                            active: true)

inactive_shop.products.create!(name "inactive product", 
                              visible: false,
                              active: false)

有时我需要更改特定商店的所有相关产品的值。我必须“取消”这些产品的范围以克服default_scope:但是我遇到了一个问题,这也删除了has_many查询:

inactive_shop.products.unscoped.map(&:name)

# ["inactive product","active product"]

但我希望只返回"inactive product"
提示:这是一个简化的例子。

scope :visible, -> { where(visible: true) }
  scope :active, -> { where(active: true) }

是不可能的,因为在我的真实的代码中作用域更加复杂。
我需要的是这样一个东西:Shop.products.all_products_of_this_shop_equally_which_scope
通过unscoped,我还可以获得整个应用程序的所有产品。Unscope还可以添加其他ShopProducts

>> Shop.last.products.to_sql
   Shop Load (1.9ms)  
     SELECT "shops".* FROM "shops" 
     ORDER BY "shops"."id" 
     DESC LIMIT $1  [["LIMIT", 1]]

=> "SELECT \"products\".* FROM \"products\"
    WHERE \"products\".\"visible\" = TRUE 
    AND \"products\".\"active\" = TRUE 
    AND \"products\".\"shop_id\" = 234"

>> Shop.last.products.unscoped.to_sql
   Shop Load (2.7ms)  
     SELECT "shops".* FROM "shops"
     ORDER BY "shops"."id" 
     DESC LIMIT $1  [["LIMIT", 1]]

=> "SELECT \"products\".* FROM \"products\""

# BUT I NEED THIS:

"SELECT \"products\".* FROM \"products\" 
 WHERE \"products\".\"shop_id\" = 234"

在Product查询中,我需要保留与商店的关系,但删除所有其他查询
非常感谢你提前

osh3o9ms

osh3o9ms1#

我认为你可以尝试使用unscope代替unscoped,它允许指定需要取消作用域的特定方法(ref),如下所示:

inactive_shop.products.unscope(where: %i[active visible]).map(&:name)

或者,如果默认范围中有许多WHERE条件,而您希望取消除shop_id之外的所有WHERE条件的范围,则可以尝试以下操作:

inactive_shop.products.unscope(
  where: inactive_shop.products.where_values_hash.except('shop_id').keys
).map(&:name)

然而,在这一点上,我会转而考虑摆脱默认范围...

相关问题