Rails ERB 验证

Rails ERB Validation

我正在尝试向我的 Rails 应用添加验证,以便在用户访问错误 ID 时显示错误消息。该项目有评论,如果我去 http://localhost:3000/reviews/:id that doesn't exist 应用程序崩溃,我想通过显示消息来防止运行时错误。

在模型中,我得到了这个验证:

class Review < ApplicationRecord
    validates :id, presence: true 
end

然后,在 reviews/show.html.erb 文件中,我尝试这样做:

<% if @review.valid? %>
 <div class='review-header'>
  ....
 </div>
<% else %>
 <% @review.errors.objects.first.full_message %>
<% end %>

这也是评论管理员:

class ReviewsController < ApplicationController
    before_action :set_review, only: [:show, :edit, :update, :destroy]
    before_action :authorize!, only: [:edit, :destroy]
    
    def index
      if params[:search]
        @reviews = Review.where("title like ?", "%#{params[:search]}%") 
      else
        @reviews = Review.all
      end
    end
  
    def new
      @review = Review.new
      @comment = Comment.new
      @comment.review_id = @review.id 
      #We need to declare the comments in the new action. 
    end
  
    def create
      @review = current_user.reviews.new(review_params)

      if @review.save
        redirect_to review_path(@review)
      else
        render 'new'
      end
    end
  
    def show
      @comment = Comment.new 
      #We also need to declare the new comment in the show action. 
    end
  
    def edit
    end
  
    def update
      if @review.update(review_params)
        redirect_to review_path(@review)
      else  
        render 'edit'
      end  
    end
  
    def destroy
      @review.destroy
      redirect_to reviews_path   
    end
  
    private

      def set_review
        @review = Review.find_by(id: params[:id])
    end 
  
      def review_params
        params.require(:review).permit(:title, :content, :category_id, :search)
      end

      def authorize! 
        authorize @review #authorize method using the Pundit gem
    end 
end

但是,我的项目一直在崩溃而不是显示消息。如果有什么办法可以使这项工作?谢谢。

问题是,如果 ID 与数据库中的评论不对应,@review 对象将是 nil,您的行 if @review.valid? 将抛出错误。

你需要一个不同的测试,比如

<% if @review.present? %>
 <div class='review-header'>
  ....
 </div>
<% else %>
 Review does not exist.
<% end %>

问题的整个设置实际上是错误的。

您不需要为 ID 添加模型验证,因为 ID 是在您插入记录时由数据库自动生成的。在大多数数据库中,主键也是 non-nullable。添加验证实际上会破坏模型,因为这会阻止您在不手动分配 id 的情况下保存记录(坏主意)。

验证控制器中是否可以找到记录也不是模型的工作。相反,您的控制器应该使用 find 以便在找不到记录时尽早退出:

class ReviewsController < ApplicationController
  before_action :set_review, only: [:show, :edit, :update, :destroy]
  before_action :authorize!, only: [:edit, :destroy]
 
  
  private

  def set_review
    @review = Review.find(params[:id])
  end 
end

这将停止执行方法和其他回调,并防止 NoMethodErrors 必然发生。如果应该 CRUD 的记录不存在,则继续处理请求是没有意义的。

默认情况下,Rails 将通过呈现位于 public/404.html 的静态 HTML 页面并返回 404 状态代码来处理未捕获的 ActiveRecord::RecordNotFound 异常。如果你想在控制器级别自定义它,请使用 rescue_from:

class ReviewsController < ApplicationController
  before_action :set_review, only: [:show, :edit, :update, :destroy]
  before_action :authorize!, only: [:edit, :destroy]
 
  rescue_from ActiveRecord::RecordNotFound, with: :not_found
  
  private

  def set_review
    @review = Review.find(params[:id])
  end

  def not_found
    # renders app/reviews/not_found.html.erb
    render :not_found, 
      status: :not_found
  end 
end

请注意,这应该在不同的视图中完成。如果您将 <% if @review.present? %> 添加到 reviews/show.html.erb 视图,您的 Rails 许可证应该被吊销,因为视图 ​​ 唯一的工作 是显示评论.

您还可以使用 config.exceptions_app 在应用程序级别配置响应。