Rails 5.1、删除多条带条件的记录
Rails 5.1, delete multiple records with conditions
我尝试根据一些条件删除数据库中的几条记录。在我谈论我的问题之前,我将解释我的应用程序是如何工作的。
用户可以创建组和 link。该用户拥有他为 link 创建的相同组。然后其他用户可以通过成员模型提供令牌(在创建组时自动创建)来加入该组。其中成员在数据库中有 user_id 和 group_id。然后,一旦用户成为组的一部分,他就可以通过组link 模型在组中共享他创建的link。其中 grouplink 有 groupd_id 和 link_id。
我设法编写了一个事实,即如果一个组中没有成员,该组就会被破坏。但是,如果他离开组,我如何设法删除组中共享的 links 用户? (当用户自动销毁时,所有 link 都被删除,所以我认为共享也应该消失,我必须尝试一下')。当用户离开组时,我会销毁他的成员记录,他就走了,但 link 仍然存在。我显示了共享的 links,你可以踢用户(成员销毁)的事实以及组中显示的组成员列表 btw。
我考虑了一些事情。我在控制台写下我做了什么
g = Group.find(66)
u = g.users.find(1)
u.links
然后给我所有来自组中用户的 link。在那旁边
g.grouplinks
会给我群组中所有共享的 link。
g.grouplinks.map(&:link_id) returns [16, 17, 14, 13, 15]
u.links.map(&:id) returns [13, 15]
现在我可以在这里做什么?我的用户要离开群组。成员记录被销毁,我如何根据用户拥有的 links 销毁那些组 links?
有没有我还不知道的魔术?
感谢您的帮助。
编辑
class User < ApplicationRecord
has_secure_password
has_many :links, dependent: :destroy
has_many :grouplinks, dependent: :destroy
has_many :members, :dependent => :destroy
has_many :groups, :through => :members
has_one :owned_group, foreign_key: "owner_id", class_name: "Group"
end
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
validates :user_id, :presence => true
validates :group_id, :presence => true
validates :user_id, :uniqueness => {:scope => [:user_id, :group_id]}
end
class Link < ApplicationRecord
has_many :grouplinks, :dependent => :destroy
belongs_to :user
end
class Grouplink < ApplicationRecord
belongs_to :group
belongs_to :link
end
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
has_many :links, through: :grouplinks
has_many :grouplinks, :dependent => :destroy
def to_param
auth_token
end
end
我认为实际上我可以在link组中添加user_id,这样我就可以delete_all根据link中的user_id s 和组 links。不知道该怎么做,也不知道是否有更好的解决方案。
编辑 2
我在模型中尝试了您的解决方案。实际上它很聪明,我没有想到这一点......
现在的问题是创建我的组link(分享link)。我有这个:
def create
user = current_user if current_user
group = user.groups.find_by(auth_token: params[:auth_token])
share = group.id
group_link = group.grouplinks.build(link_id: params[:link_id])
gl = group.grouplinks
if gl.where(group_id: share).where(link_id: params[:link_id]).exists?
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path
else
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render 'new'
end
end
end
这显然不再有效,当我尝试共享 link 时出现此错误:First argument in form cannot contain nil or be empty
<%= form_for @grouplink do |f| %>
.
我试过这样改:
def create
group = Group.find_by(auth_token: params[:auth_token])
share = group.id
group_link = group.grouplinks.build(link_id: params[:link_id])
gl = group.grouplinks
if gl.where(group_id: share).where(link_id: params[:link_id]).exists?
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path
else
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render 'new'
end
end
end
但它也不起作用
您要找的是dependent :delete_all
在你的 Group
模型中,你应该有这样一行:
has_many :links, dependent :delete_all
这就是说,该群有很多链接,如果你销毁该群,则销毁所有相关链接。
在您的 Member
模型中,您可以使用 after_destroy
回调在成员记录被销毁后销毁群组中的所有用户链接:
class Member < ApplicationRecord
after_destroy do |record|
record.user.links.each { |link| link.grouplinks.where(group_id: record.group.id).destroy_all }
end
belongs_to :user
belongs_to :group
...
end
此外,我建议您将 Member
更改为 Membership
以便更清楚。
怎么样:
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
has_many :group_links, dependent: :destroy
validates :user_id, :presence => true
validates :group_id, :presence => true
validates :user_id, :uniqueness => {:scope => [:user_id, :group_id]}
end
和
class Grouplink < ApplicationRecord
belongs_to :link
belongs_to :member
end
现在,当 Member
记录被销毁时(即 user
被踢出或离开 group
),任何 links
与 group
(即group_links
)也被销毁。但是,如果 user
在另一个 group
中共享了 link
,则 link
将继续与其他 groups
共享。
正如@Pablo 在评论中提到的,您可能还想这样做:
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :grouplinks, through: :members
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
has_many :links, through: :grouplinks
def to_param
auth_token
end
end
这将允许你做:
group.grouplinks
我也同意@amr-el-bakry 的观点,Member
有点令人困惑。我建议 GroupUser
,因为它很清楚地表明它是 Group
和 User
之间的关联。
此外,我认为说 GroupLink
比 Grouplink
可能更传统一些。或者,如果您想坚持基于关联 类 的命名,也许 MemberLink
。如果将 Member
更改为 GroupUser
,则可能 GroupUserLink
。
我认为您的 create
代码应该类似于:
def create
if group
if member
if link
unless group_link
@group_link = member.group_links.build(link: link)
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render :new
end
else
flash[:error] = "You shared this link in '#{group.name}' already."
else
flash[:error] = "That link does not exist."
redirect_to somewhere #fix this
end
else
flash[:error] = "You must be a member of this group to add a link."
redirect_to somewhere #fix this
end
else
flash[:error] = "There is no group with that token."
redirect_to somewhere #fix this
end
end
private
def group
@group ||= Group.find_by(auth_token: params[:auth_token])
end
def member
@member ||= current_user.members.where(group: group)
end
def link
@link ||= Link.find_by(id: params[:link_id])
end
def group_link
@group_link ||= member.group_links.where(link: link)
end
您可以将其写成:
def create
flash[:error] = "There is no group with that token."
redirect_to somewhere unless group
flash[:error] = "You must be a member of this group to add a link."
redirect_to somewhere unless member
flash[:error] = "That link does not exist."
redirect_to somewhere unless link
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path if group_link
flash[:error] = nil
@group_link = member.group_links.build(link: link)
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render :new
end
end
但我不记得那些重定向是否会让你心痛。
我认为最好的想法是 group_links 属于一个成员和一个 link(而不是一个组和一个 link)。而一个会员(不是用户)有很多group_links。当您销毁成员时,它会销毁 group_links。
编辑
这是 jvillian 在他的回答中建议的,就在我之前。所以我相信他的回答是正确的(我在评论中提出了一些小的改进,jvillian 肯定会接受并添加 :-)。
EDIT2
关于您在应用jvillian建议后遇到的问题,在创建新组时link,必须由成员(而不是组)完成。因此,在创建操作中,您必须搜索成员(按 user_id 和 group_id)并将组 link 创建为 member.grouplinks.build
我尝试根据一些条件删除数据库中的几条记录。在我谈论我的问题之前,我将解释我的应用程序是如何工作的。
用户可以创建组和 link。该用户拥有他为 link 创建的相同组。然后其他用户可以通过成员模型提供令牌(在创建组时自动创建)来加入该组。其中成员在数据库中有 user_id 和 group_id。然后,一旦用户成为组的一部分,他就可以通过组link 模型在组中共享他创建的link。其中 grouplink 有 groupd_id 和 link_id。
我设法编写了一个事实,即如果一个组中没有成员,该组就会被破坏。但是,如果他离开组,我如何设法删除组中共享的 links 用户? (当用户自动销毁时,所有 link 都被删除,所以我认为共享也应该消失,我必须尝试一下')。当用户离开组时,我会销毁他的成员记录,他就走了,但 link 仍然存在。我显示了共享的 links,你可以踢用户(成员销毁)的事实以及组中显示的组成员列表 btw。
我考虑了一些事情。我在控制台写下我做了什么
g = Group.find(66)
u = g.users.find(1)
u.links
然后给我所有来自组中用户的 link。在那旁边
g.grouplinks
会给我群组中所有共享的 link。
g.grouplinks.map(&:link_id) returns [16, 17, 14, 13, 15]
u.links.map(&:id) returns [13, 15]
现在我可以在这里做什么?我的用户要离开群组。成员记录被销毁,我如何根据用户拥有的 links 销毁那些组 links?
有没有我还不知道的魔术?
感谢您的帮助。
编辑
class User < ApplicationRecord
has_secure_password
has_many :links, dependent: :destroy
has_many :grouplinks, dependent: :destroy
has_many :members, :dependent => :destroy
has_many :groups, :through => :members
has_one :owned_group, foreign_key: "owner_id", class_name: "Group"
end
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
validates :user_id, :presence => true
validates :group_id, :presence => true
validates :user_id, :uniqueness => {:scope => [:user_id, :group_id]}
end
class Link < ApplicationRecord
has_many :grouplinks, :dependent => :destroy
belongs_to :user
end
class Grouplink < ApplicationRecord
belongs_to :group
belongs_to :link
end
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
has_many :links, through: :grouplinks
has_many :grouplinks, :dependent => :destroy
def to_param
auth_token
end
end
我认为实际上我可以在link组中添加user_id,这样我就可以delete_all根据link中的user_id s 和组 links。不知道该怎么做,也不知道是否有更好的解决方案。
编辑 2
我在模型中尝试了您的解决方案。实际上它很聪明,我没有想到这一点...... 现在的问题是创建我的组link(分享link)。我有这个:
def create
user = current_user if current_user
group = user.groups.find_by(auth_token: params[:auth_token])
share = group.id
group_link = group.grouplinks.build(link_id: params[:link_id])
gl = group.grouplinks
if gl.where(group_id: share).where(link_id: params[:link_id]).exists?
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path
else
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render 'new'
end
end
end
这显然不再有效,当我尝试共享 link 时出现此错误:First argument in form cannot contain nil or be empty
<%= form_for @grouplink do |f| %>
.
我试过这样改:
def create
group = Group.find_by(auth_token: params[:auth_token])
share = group.id
group_link = group.grouplinks.build(link_id: params[:link_id])
gl = group.grouplinks
if gl.where(group_id: share).where(link_id: params[:link_id]).exists?
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path
else
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render 'new'
end
end
end
但它也不起作用
您要找的是dependent :delete_all
在你的 Group
模型中,你应该有这样一行:
has_many :links, dependent :delete_all
这就是说,该群有很多链接,如果你销毁该群,则销毁所有相关链接。
在您的 Member
模型中,您可以使用 after_destroy
回调在成员记录被销毁后销毁群组中的所有用户链接:
class Member < ApplicationRecord
after_destroy do |record|
record.user.links.each { |link| link.grouplinks.where(group_id: record.group.id).destroy_all }
end
belongs_to :user
belongs_to :group
...
end
此外,我建议您将 Member
更改为 Membership
以便更清楚。
怎么样:
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
has_many :group_links, dependent: :destroy
validates :user_id, :presence => true
validates :group_id, :presence => true
validates :user_id, :uniqueness => {:scope => [:user_id, :group_id]}
end
和
class Grouplink < ApplicationRecord
belongs_to :link
belongs_to :member
end
现在,当 Member
记录被销毁时(即 user
被踢出或离开 group
),任何 links
与 group
(即group_links
)也被销毁。但是,如果 user
在另一个 group
中共享了 link
,则 link
将继续与其他 groups
共享。
正如@Pablo 在评论中提到的,您可能还想这样做:
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :grouplinks, through: :members
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
has_many :links, through: :grouplinks
def to_param
auth_token
end
end
这将允许你做:
group.grouplinks
我也同意@amr-el-bakry 的观点,Member
有点令人困惑。我建议 GroupUser
,因为它很清楚地表明它是 Group
和 User
之间的关联。
此外,我认为说 GroupLink
比 Grouplink
可能更传统一些。或者,如果您想坚持基于关联 类 的命名,也许 MemberLink
。如果将 Member
更改为 GroupUser
,则可能 GroupUserLink
。
我认为您的 create
代码应该类似于:
def create
if group
if member
if link
unless group_link
@group_link = member.group_links.build(link: link)
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render :new
end
else
flash[:error] = "You shared this link in '#{group.name}' already."
else
flash[:error] = "That link does not exist."
redirect_to somewhere #fix this
end
else
flash[:error] = "You must be a member of this group to add a link."
redirect_to somewhere #fix this
end
else
flash[:error] = "There is no group with that token."
redirect_to somewhere #fix this
end
end
private
def group
@group ||= Group.find_by(auth_token: params[:auth_token])
end
def member
@member ||= current_user.members.where(group: group)
end
def link
@link ||= Link.find_by(id: params[:link_id])
end
def group_link
@group_link ||= member.group_links.where(link: link)
end
您可以将其写成:
def create
flash[:error] = "There is no group with that token."
redirect_to somewhere unless group
flash[:error] = "You must be a member of this group to add a link."
redirect_to somewhere unless member
flash[:error] = "That link does not exist."
redirect_to somewhere unless link
flash[:error] = "You shared this link in '#{group.name}' already."
redirect_to mylinks_path if group_link
flash[:error] = nil
@group_link = member.group_links.build(link: link)
if group_link.save
group_link.toggle!(:shared)
flash[:success] = "You shared your link in '#{group.name}'."
redirect_to mylinks_path
else
render :new
end
end
但我不记得那些重定向是否会让你心痛。
我认为最好的想法是 group_links 属于一个成员和一个 link(而不是一个组和一个 link)。而一个会员(不是用户)有很多group_links。当您销毁成员时,它会销毁 group_links。
编辑
这是 jvillian 在他的回答中建议的,就在我之前。所以我相信他的回答是正确的(我在评论中提出了一些小的改进,jvillian 肯定会接受并添加 :-)。
EDIT2
关于您在应用jvillian建议后遇到的问题,在创建新组时link,必须由成员(而不是组)完成。因此,在创建操作中,您必须搜索成员(按 user_id 和 group_id)并将组 link 创建为 member.grouplinks.build