如何以 Ruby / Rails 方式更新 kwargs?

How to update kwargs the Ruby / Rails way?

我在 GraphQL 解析器中有这个:

def resolve(id:, tag_ids: nil, **kwargs)
  article = current_user.articles.find(id)
  tags = tag_ids ? Tag.where(id: tag_ids) : article.tags
  article.update!(tags: tags, **kwargs)
  article
end

如果标签不是 nil,我基本上只想将 tags key/value 对传递给 article.update!。我正在通过将其设置回 article.tags.

来做一个丑陋的黑客攻击

我该如何以正确的方式做到这一点,我可以做这样的事情吗?

def resolve(id:, tag_ids: nil, **kwargs)
  article = current_user.articles.find(id)
  tags = tag_ids ? Tag.where(id: tag_ids) : nil
  if tags then kwargs.append!(tags: tags)
  article.update!(**kwargs)
  article
end

如果没有执行此操作的标准方法,有什么更好的方法来完成此操作以减少混乱并有效?

注意 建议的代码是破坏性的,会删除未传入的标签。如果(相反)您希望标签是附加的,请参阅更新 #2。

如果是这样的话,那你就非常接近了。 kwargs 只是一个简单的散列,所以我会做如下的事情:

def resolve(id:, tag_ids: nil, **kwargs)
  article = current_user.articles.find(id)
  kwargs[:tags] = Tag.where(id: tag_ids) if tag_ids
  article.update!(**kwargs)
  article
end

我喜欢对某个对象进行操作然后返回的模式是tap。然而,对于 ruby 的新手/不太熟悉该模式的人来说,这可能会造成混淆,所以 YYMV。

def resolve(id:, tag_ids: nil, **kwargs)
  current_user.articles.find(id).tap do |article|
    kwargs[:tags] = Tag.where(id: tag_ids) if tag_ids
    article.update!(**kwargs)
  end
end

更新

根据您的模型关联的设置方式,您可以完全跳过查找。比如文章classhas_many :tags,那么ActiveRecord为你提供了tag_ids=方法

在这种情况下你可以这样做:

def resolve(id:, tag_ids: nil, **kwargs)
  article = current_user.articles.find(id)
  kwargs[:tag_ids] = tag_ids if tag_ids
  article.update!(**kwargs)
  article
end

更新 #2

如果您想将传入的标签添加到现有数组中,您需要明确地这样做,例如:

def resolve(id:, tag_ids: nil, **kwargs)
  article = current_user.articles.find(id)
  kwargs[:tag_ids] = article.tag_ids + tag_ids if tag_ids
  article.update!(**kwargs)
  article
end