Rails 高级约束将变量从路由传递到控制器

Rails Advanced Constraint pass variable from Routes to Controller

给出

# routes.rb
get ':friend_slug', to: 'friend#show', constraints: FriendConstraint.new

# friend_constraint.rb
def matches?(request)
  friend = Friend.find_by(slug: request.params['friend_slug'])
  friend.present?
end

由于我已经查找并在我的路由约束中包含 friend,我如何 save/pass 我的控制器变量 friend 以避免重复查找?

目前,我正在控制器中执行完全相同的行,Friend.find_by(slug: request.params['friend_slug'])

没有干净的方法可以将变量从约束传送到控制器。

肮脏的方法是直接在 request 对象上设置实例变量。

# friend_constraint.rb
def matches?(request)
  friend = Friend.find_by(slug: request.params['friend_slug'])

  return false if friend.blank?

  request.instance_variable_set('@namespace_friend', friend)
end

# friends_controller.rb
...
friend = request.instance_variable_get('@namespace_friend')
...

@namespace_ 这样您就不会与正确的请求变量发生冲突。

绝对不推荐用于生产,但这是一个有趣的练习。

我找到了解决办法。

创建一个classCurrent,这里可以设置任意变量。

app/models/current.rb

class Current < ActiveSupport::CurrentAttributes
  attribute :friend
end

在constraint中,可以设置Current.friend

# routes.rb
get ':friend_slug', to: 'friend#show', constraints: FriendConstraint.new

# friend_constraint.rb
def matches?(request)
  friend = Friend.find_by(slug: request.params['friend_slug'])
  Current.friend = friend ## here I set friend
  friend.present?
end

现在,您可以在任何 controllermodelview 或其他地方使用 Current.friend

如何向 request.params 添加额外的密钥?像这样:

# friend_constraint.rb
def matches?(request)
  friend = Friend.find_by(slug: request.params['friend_slug'])
  request.params[:friend] = friend 
  friend.present?
end