【发布时间】:2015-11-13 20:20:00
【问题描述】:
在我的模型 MediaFileAsset 上,我通过包含的库添加了以下内容:
default_scope ->{eager_load(:service_asset_core).where(service_asset_cores: {archived: false})}
抛开不使用 default_scopes 的原因,有没有办法使用 unscope 从查询中删除此范围?
例如,也许有人经过我
assets = MediaFileAsset.where(custom_conditions)
我想计算所有这些忽略service_asset_cores 上的archived 字段。如果archived 是media_file_assets 的字段,我可以使用
assets.unscope(where: :archived).count
但这在这里不起作用,因为archived 是ServiceAssetCore 上的一个字段,而不是MediaFileAsset。
使用unscoped 和unscope(:where) 可以删除存档条件,但这些删除的不仅仅是那个条件,这不是我想要的。我相信这就是为什么首先添加 unscope() 方法的原因,我正在尝试了解是否可以使用它来删除连接表上的查询条件。
供参考:
2.2.2 > MediaFileAsset.unscoped.count
(505.8ms) SELECT COUNT(*) FROM `media_file_assets`
=> 3078951
为了取消具体的 where: :archived 子句的范围,我已经尝试过:
2.2.2 > MediaFileAsset.unscope(where: {service_asset_cores: :archived}).count
(0.5ms) SELECT COUNT(DISTINCT `media_file_assets`.`id`) FROM `media_file_assets` LEFT OUTER JOIN `service_asset_cores` ON `service_asset_cores`.`service_asset_id` = `media_file_assets`.`id` AND `service_asset_cores`.`service_asset_type` = 'MediaFileAsset' WHERE `service_asset_cores`.`archived` = 0
=> 10
2.2.2 > MediaFileAsset.all.merge(ActsAsServiceAsset::ServiceAssetCore.unscoped).count
(0.5ms) SELECT COUNT(DISTINCT `media_file_assets`.`id`) FROM `media_file_assets` LEFT OUTER JOIN `service_asset_cores` ON `service_asset_cores`.`service_asset_id` = `media_file_assets`.`id` AND `service_asset_cores`.`service_asset_type` = 'MediaFileAsset' WHERE `service_asset_cores`.`archived` = 0
=> 10
2.2.2 > MediaFileAsset.unscope(where: :archived).count
(0.8ms) SELECT COUNT(DISTINCT `media_file_assets`.`id`) FROM `media_file_assets` LEFT OUTER JOIN `service_asset_cores` ON `service_asset_cores`.`service_asset_id` = `media_file_assets`.`id` AND `service_asset_cores`.`service_asset_type` = 'MediaFileAsset' WHERE `service_asset_cores`.`archived` =
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1: SELECT COUNT(DISTINCT `media_file_assets`.`id`) FROM `media_file_assets` LEFT OUTER JOIN `service_asset_cores` ON `service_asset_cores`.`service_asset_id` = `media_file_assets`.`id` AND `service_asset_cores`.`service_asset_type` = 'MediaFileAsset' WHERE `service_asset_cores`.`archived` =
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1: SELECT COUNT(DISTINCT `media_file_assets`.`id`) FROM `media_file_assets` LEFT OUTER JOIN `service_asset_cores` ON `service_asset_cores`.`service_asset_id` = `media_file_assets`.`id` AND `service_asset_cores`.`service_asset_type` = 'MediaFileAsset' WHERE `service_asset_cores`.`archived` =
2.2.2 > MediaFileAsset.all.merge(ActsAsServiceAsset::ServiceAssetCore.unscope(where: :archived)).count
# output omitted, same error as pervious
最后两个似乎是 Rails (4.2.3) 错误,因为生成的 SQL 无效。也许这就是我需要去的地方,但错误就在我的路上。我应该尝试另一种方法,还是我被不可避免的 default_scope 的恐怖所困扰?
【问题讨论】:
-
我没用过
unscoped,但也许unscoped.where(service_asset_cores: :archived) -
不幸的是无法工作。 unscoped 删除所有以前附加的范围和查询方法。 unscope(*args) 可以删除特定的查询,但我无法删除连接模型上的查询,这就是问题所在。
-
啊,我的意思是坐在
unscope而不是unscoped,但我猜这仍然行不通。如果有任何方法可以删除默认范围,但我认为您还有其他考虑因素会阻止... -
是的。该库将包含在数十个普遍存在的模型中,并且整个开发团队都非常倾向于不必在任何地方指定诸如“活动”之类的明确范围,因为大多数其他开发人员对存档资产不感兴趣.我试图让他们留在身边以分析错误和其他故障,但我必须对其他开发人员的担忧透明地这样做。一种可能的解决方案是放弃 service_asset_cores 表并将列添加到包含该模块的每个模型中,但这是 (a) 大量迁移,并且 (b) 对结构更改的鲁棒性较差。
标签: ruby-on-rails ruby-on-rails-4 activerecord rails-activerecord