1

我继承了一些 Rails 代码,用于检查用户是否在由 before 过滤器调用的方法中定义:

before_filter :get_user

def get_user
  @user = User.find(params[:id])
  if !@user
    return false
  end
end

现在,问题是这不起作用:) 如果找不到用户,我们不会从控制器返回,我们只是从get_user()方法返回,然后在设置为的show()orupdate()方法中继续执行。@usernil

get_user()我的简单解决方案是在if@user为 nil时添加重定向:

def get_user
  @user = User.find(params[:id])
  if !@user
    redirect_back
    return false
  end
end

现在,我的测试通过了,世界上的一切似乎都是正确的。但是......我不明白发生了什么。有人可以解释一下为什么 return inget_user()没有完全停止控制器中的执行,而是让我们脱离get_user()并导致我们陷入最初调用的控制器方法?

谢谢!

4

3 回答 3

4

http://guides.rubyonrails.org/action_controller_overview.html#filters

“该方法只是在闪存中存储一​​条错误消息并在用户未登录时重定向到登录表单。如果“之前”过滤器呈现或重定向,则该操作将不会运行。如果有其他过滤器计划在之后运行那个过滤器,它们也被取消了。”

非常不言自明,但本质是您无法返回以在过滤器中停止执行。

于 2013-07-22T21:08:34.573 回答
1

在方法内部返回只是返回并破坏该方法,仅此而已。Se 代码如下。

def foo
  return "foo"
  return "bar"
end

puts my_method # this will puts "foo" and the second return will never be called.

但是,在 ruby​​ 中,您仍然可以在使用ensure.

def bar
  return "bar"
ensure
  @bar = 'Hello world'
end

puts bar # returns and prints "bar" 
puts @bar # prints "Hello world" because the ensure part was still executed

请记住,您的方法中最后执行的代码将被返回,因此您并不总是需要return在您的值之前编写。如果你的方法中有一个 ensure 部分,那么如果你还没有返回一些东西,那么之前最后执行的代码将被返回。

并且无需在之前的过滤器中返回 false。如果我记得 3.1 版之前的右导轨确实在之前的过滤器返回虚假值时停止了控制器。Nil 在 ruby​​ 中仍然是虚假的,并且要删除一些行,您可以像下面这样编写过滤器,因为如果没有找到用户,则@user在此示例中将为 nil。

def get_user
  @user = User.find_by id: params[:id] # I use find_by to prevent exception, else we may return an 500 error which you may or may not want.
  redirect_back unless @user
end
于 2013-07-22T21:34:29.713 回答
0

我会这样重写这段代码

def get_user
  redirect_back if User.where(id: params[:id]).empty?
end

有两个原因。首先,如果您可以以更简单的方式检查它,为什么要这样做。其次,find如果找不到对象,则引发异常,因此此检查根本没有意义!

于 2013-07-22T21:11:59.340 回答