我想在Rails中“伪造”一个404页面。在PHP中,我只会发送一个带有错误代码的报头:

header("HTTP/1.0 404 Not Found");

Rails如何做到这一点?


当前回答

routes.rb
  get '*unmatched_route', to: 'main#not_found'

main_controller.rb
  def not_found
    render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
  end

其他回答

HTTP 404状态

要返回404报头,只需使用render方法的:status选项。

def action
  # here the code

  render :status => 404
end

如果希望呈现标准404页面,可以在方法中提取该特性。

def render_404
  respond_to do |format|
    format.html { render :file => "#{Rails.root}/public/404", :layout => false, :status => :not_found }
    format.xml  { head :not_found }
    format.any  { head :not_found }
  end
end

把它称为你的行动

def action
  # here the code

  render_404
end

如果希望操作呈现错误页面并停止,只需使用return语句。

def action
  render_404 and return if params[:something].blank?

  # here the code that will never be executed
end

ActiveRecord和HTTP 404

还要记住,Rails挽救了一些ActiveRecord错误,例如ActiveRecord::RecordNotFound显示404错误页面。

这意味着您不需要自己拯救这个操作

def show
  user = User.find(params[:id])
end

用户。find在用户不存在时引发ActiveRecord::RecordNotFound。这是一个非常强大的功能。请看下面的代码

def show
  user = User.find_by_email(params[:email]) or raise("not found")
  # ...
end

您可以通过将检查委托给Rails来简化它。简单地使用bang版本。

def show
  user = User.find_by_email!(params[:email])
  # ...
end

不要自己渲染404页面,没有理由;Rails已经内置了这个功能。如果你想显示一个404页面,在ApplicationController中创建一个render_404方法(或者我称之为not_found),如下所示:

def not_found
  raise ActionController::RoutingError.new('Not Found')
end

Rails还以同样的方式处理AbstractController::ActionNotFound和ActiveRecord::RecordNotFound。

这样做有两个好处:

1)它使用Rails内置的rescue_from处理程序来呈现404页面 2)它会中断代码的执行,让你做一些不错的事情,比如:

  user = User.find_by_email(params[:email]) or not_found
  user.do_something!

而不用写丑陋的条件语句。

作为奖励,它在测试中也非常容易处理。例如,在rspec集成测试中:

# RSpec 1

lambda {
  visit '/something/you/want/to/404'
}.should raise_error(ActionController::RoutingError)

# RSpec 2+

expect {
  get '/something/you/want/to/404'
}.to raise_error(ActionController::RoutingError)

和小型试验:

assert_raises(ActionController::RoutingError) do 
  get '/something/you/want/to/404'
end

OR从控制器动作中找不到的Rails渲染404中引用更多信息

你也可以使用渲染文件:

render file: "#{Rails.root}/public/404.html", layout: false, status: 404

你可以选择是否使用该布局。

另一种选择是使用Exceptions来控制它:

raise ActiveRecord::RecordNotFound, "Record not found."
<%= render file: 'public/404', status: 404, formats: [:html] %>

只需将此添加到要呈现到404错误页面的页面,就完成了。

我想对任何不是管理员的登录用户抛出一个“正常的”404,所以我最终在Rails 5中写了这样的东西:

class AdminController < ApplicationController
  before_action :blackhole_admin

  private

  def blackhole_admin
    return if current_user.admin?

    raise ActionController::RoutingError, 'Not Found'
  rescue ActionController::RoutingError
    render file: "#{Rails.root}/public/404", layout: false, status: :not_found
  end
end