【问题标题】:Rails: destroying multiple user-to-user associationsRails:破坏多个用户到用户的关联
【发布时间】:2014-03-15 02:50:16
【问题描述】:

我有一个名为Block 的模型,它有一个blocker_id(一个user_id)和一个blocked_user_id 字段(也是一个user_id)。 Block 模型允许一个用户阻止另一个用户。当一个用户阻止另一个用户时,我希望它使用Block 类的before_save 方法来破坏他们之间的Relationship。 Relationship 表有一个follower_id 和一个followed_id。

这就是事情变得棘手的地方。我知道我可以通过使用多个return if Relationship.xyz.nil? 语句然后使用多个Relationship.find_by(follower_id: , followed_id: ).destroy 语句来实现这个目标,但这变得过于复杂,因为每个blocker 和blocked_user 都可以是follower 和@987654336 @id,两者都有,或者两者都没有。有没有更简单的方法来做到这一点?

这是我的模型供参考:(Block 类也有一个 blocked_post 字段,我对此没有任何问题)

class Block < ActiveRecord::Base

validates :blocker_id, presence: true
validates :blocked_user_id, uniqueness: {scope: :blocker_id}, allow_nil: true
validates :blocked_post_id, uniqueness: {scope: :blocker_id}, allow_nil: true 
validate  :blocked_user_or_post
after_validation :validate_block
before_save :destroy_blocked_relationships


belongs_to(
    :blocker,
    class_name: "User"
    )

has_one(
    :blocked_user,
    class_name: "User"
    )

has_one(
    :blocked_post,
    class_name: "Post"
    )

private

def blocked_user_or_post
  blocked_user_id.blank? ^ blocked_post_id.blank?
end


def validate_block
  if blocked_user_id.present?
    !(blocker_id == blocked_user_id)
  elsif blocked_post_id.present?
    blocked_post = Post.find_by(id: self.blocked_post_id).user_id
    !(blocker_id == blocked_post)
  else
    false
  end
end

def destroy_blocked_relationships
  #my over-complex code was here
end

end

relationship.rb:

class Relationship < ActiveRecord::Base


validates :follower_id, :followed_id, presence: {message: 'Need an eligible follower and followee id'}
validates :followed_id, uniqueness: { scope: :follower_id}


belongs_to(
   :follower, 
   class_name: "User"
   )

belongs_to(
   :followed, 
   class_name: "User"
   )
end

如果有任何不需要大量代码的方法来做到这一点,我真的很想知道。提前致谢。

【问题讨论】:

  • 在这一行中,您是不是要为变量命名其他名称? blocked_post = Post.find_by(id: self.blocked_post_id).user_id

标签: ruby-on-rails ruby callback associations


【解决方案1】:

我不确定您的确切用例,但我对人们可以互相关注的系统的想法,似乎阻止者总是被关注的人。如果是这种情况,这里有一个实现:

def destroy_blocked_relationships
  Relationship.where(follower_id:blocked_user_id, followed_id:blocker_id).destroy_all
  true
end

如果阻止某人被关注也有意义,您可以添加以下内容:

Relationship.where(follower_id:blocker_id, followed_id:blocked_user_id).destory_all

这里全部都在一起,如果没有关系,则停止保存块:

before_save :destroy_blocked_relationships

def destroy_blocked_relationships
  relationships = Relationship.where("(follower_id = ? AND followed_id = ?) OR (followed_id = ? AND follower_id = ? )", blocked_user_id, blocker_id, blocked_user_id, blocker_id)
  relationships.destroy_all
  relationships.present?  # Omit this line if the save should continue regardless
end

【讨论】:

  • 我认为这不会破坏blocker是follower和blocked_user是follower的关系,对吧?
  • 好的,现在唯一的问题是我需要检查这些是否为.nil?在我尝试删除它们之前,因为这是一个验证,这两个用户很可能根本没有任何关系。当你添加一个 if relationship.xyz.nil?两次,然后我就回到了我开始的地方
  • 如果没有关系,Relationship.where(...) 的结果将是一个空集,不会破坏任何东西。
  • 不,就像我说的,它作为回调方法运行,所以如果没有关系,它将返回 false 并且不会保存用户-用户块,并且不会保存用户发布块,因为也失败了。即使回调是 after_save
  • 哦,是的 - 因为它在 ActiveRecord 回调中,如果您希望它继续保存,则需要返回 true。如果没有关系,我将添加另一个示例以防您不想保存。
【解决方案2】:

这是我的理解:

  • 块是两个用户之间的关系,或者是用户和帖子之间的关系
  • 在用户 A 和帖子 X 之间创建块时,也会在用户 A 和用户 B 之间创建一个隐式块,其中用户 B 是帖子 X 的作者

考虑制作两个模型,BlockedPost 和 BlockedUser。然后,创建两个#make 方法。这使得所有相关逻辑更容易推理。

# class BlockedPost
def make(user, post)
  transaction do
    create!(user: user, post: post)
    BlockedUser.make(user, post.author)
  end
end

# class BlockedUser
def make(user, blocked_user)
  transaction do
    create!(user: user, blocked_user: blocked_user)
    Relationship.where(follower: user, following: blocked_user).destroy_all
    Relationship.where(follower: blocked_user, following: user).destroy_all
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 2012-03-18
    • 1970-01-01
    • 2018-07-26
    • 2017-03-14
    • 1970-01-01
    • 2010-11-20
    相关资源
    最近更新 更多