我试图删除所有不再有organizations
的{{1}}。
使用以下代码,我可以找到我想要删除的所有记录:
users
当我添加Organization.includes(:users)
.where(users: { id: nil })
.references(:users)
时,如果我没有包含delete_all
,我会得到同样的错误:
references
我可以用纯SQL编写解决方案,但是我不明白为什么当我添加PG::UndefinedTable: ERROR: missing FROM-clause entry for table "users"
语句时Rails不会保留对users
的引用。
以下是一些更多细节:
delete_all
答案 0 :(得分:2)
我发现includes
仅对急切加载很有用(并且很少处理我的案例),当与references
结合使用时,它会生成某些内容完全疯了(使用类似tN_rM
之类的每个字段别名),即使它实际上有LEFT OUTER JOIN
...如果 可以帮助<一旦delete_all
出现,强>消失!
我发现使用exists
会更清晰,更简单。它是Arel(并且没有任何意义可以避免它,无论如何它都在ActiveRecord的引擎盖下),但它只是一个很小的部分,它几乎没有引人注目:
Organization.where(
User.where('users.organization_id = organizations.id').exists.not
)
或者,如果这个SQL字符串看起来不太好,请使用更多的Arel,这样会引人注意:
Organization.where(
User.where(organization_id: Organization.arel_table[:id]).exists.not
) # I tend to extract these ^^^^^^^^^^^^^^^^^^^^^^^ into local variables
它处理链接.delete_all
就好了,因为它不是(语法上)一个连接,即使它实际上等同于一个连接。
SQL有一个EXISTS
运算符,其功能与连接类似,但无法从连接表中选择字段。它形成一个有效的布尔表达式,可以否定和投入WHERE
- 条件。
在“无SQL”表单中,我使用表达式“表的列”,结果证明它可用于Rails的哈希条件。这是一个偶然的发现,是Arel的少数用途之一,它不会使代码过于庞大。
答案 1 :(得分:0)
我不确定您打算如何在MVC框架中实现此功能,但通过模型操作进行组织清除似乎很简洁。每当用户被删除时,检查组织是否有剩余的成员。
User.rb中的
class User < ActiveRecord::Base
before_destroy :close_user
...
def user_organization
Organization.where(user_id: id)
end
private
def close_user
unless user_organization.users.any?
user_organization.destroy
end
end
end
已添加将回调删除解决方案应用于属于多个组织成员的用户
如果用户有多个组织
class User < ActiveRecord::Base
before_destroy :close_user
...
def user_organizations
Organization.where(user_id: id)
end
private
def close_user
user_organization.find_each do |organization|
unless organization.users.any?
organization.destroy
end
end
end
警告:这没有经过测试,语法没有失败。我没有足够的数据来测试它,但我认为它会起作用。但这意味着在每次删除用户之后运行此操作,这是一个系统架构决策。如果它是一个选项,它可能值得一试。