Rails ERB 验证

发布于 2025-01-09 01:07:27 字数 2030 浏览 1 评论 0原文

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

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

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

但是,我的项目不断崩溃而不是显示一条消息。如果有什么办法可以让我完成这项工作吗?谢谢。

I'm trying to add a validation to my Rails app in order to display an error message if the user goes to the wrong id. The project has reviews, if I go to http://localhost:3000/reviews/:id that doesn't exist the app crashes, I'd like to prevent the runtime error by displaying a message.

In the model, I got this validation:

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

Then, in the reviews/show.html.erb file, I'm trying this:

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

This is also the Reviews Controller:

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

However, my project keep crashing rather than showing a message. If there's any way I can make this work? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷路的信 2025-01-16 01:07:28

这个问题的整个设置实际上被打破了。

您不需要为 id 添加模型验证,因为 id 是在您插入记录时由数据库自动生成的。在大多数数据库上,主键也是不可为空的。添加验证实际上会破坏模型,因为这会阻止您在不手动分配 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

这会停止方法和其他回调的执行,并防止绑定到的 NoMethodError发生。如果应该进行 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 在应用程序级别配置响应。

The whole setup of the question is actually broken.

You don't need to add a model validation for the id since ids are automatically generated by the database when you insert records. On most databases primary keys are also non-nullable. Adding the validation will actually break the model as will prevent you from saving records without manually assigning an id (bad idea).

Its also not the models job to verify that a record can be found in the controller. Instead your controller should use find so that it bails early if the record cannot be found:

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

This halts execution of the method and other callbacks and prevents the NoMethodErrors that are bound to occur. There is no sense in continuing to process a request if the record that its supposed to CRUD doesn't exist.

By default Rails will handle an uncaught ActiveRecord::RecordNotFound exception by rendering a static HTML page located at public/404.html and returning a 404 status code. If you want to customize this on the controller level use 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

Note that this should be done in different view. If you add a <% if @review.present? %> to your reviews/show.html.erb view you should get your Rails licence revoked as the views one and only job is to display the review.

You can also configure the responses on the application level with config.exceptions_app.

一影成城 2025-01-16 01:07:28

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

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

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

The problem is that if the ID does not correspond to a review in the database, the @review object will be nil, and your line if @review.valid? will throw an error.

You need a different test, something like

<% if @review.present? %>
 <div class='review-header'>
  ....
 </div>
<% else %>
 Review does not exist.
<% end %>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文