Rails Advanced Constraint从路径到控制器的传递变量

时间:2019-08-02 03:08:48

标签: ruby-on-rails optimization routing

给予

# 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,如何为控制器保存/传递变量friend以避免控制器双重查询?

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

3 个答案:

答案 0 :(得分:2)

我找到了解决方案。

创建一个类Current,在这里你可以设置任何变量。

app/models/current.rb

class Current < ActiveSupport::CurrentAttributes
  attribute :friend
end

在约束中,您可以设置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

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

答案 1 :(得分:0)

没有干净的方法将变量从约束携带到控制器。

肮脏的方法是直接在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_,因此您永远不会与适当的请求变量发生冲突。

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

答案 2 :(得分:0)

request.params 添加额外的密钥怎么样?像这样:

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