简体   繁体   中英

rails rubocop use && instead of and with render and return

I have been stuck on this issue for some time now, but keep skipping over it. If I follow the cop guidelines here and change this to && my routes break. They are connected to my routes via:

  # Override Error Codes
  match '/404', to: 'error#four_oh_four', via: :all
  match '/422', to: 'error#four_twenty_two', via: :all
  match '/500', to: 'error#five_hundred', via: :all

Do you recommend disabling this cop for this issue or is there a better way to adjust this?

在此处输入图片说明

class ErrorController < ApplicationController
  before_filter :ensure_trailing_slash
  before_action :load_log_service

  def javascript_disabled
    @log_service.capture_message(view_context.time_stamp('javascript_disabled'), 'error_scope')
    render_error_application_requirements t('system_requirements.minimum_settings.javascript_disabled')
  end

  def system_requirements
    @log_service.capture_message(view_context.time_stamp('system_requirements'), 'error_scope')
    render_error_application_requirements t('system_requirements.minimum_settings.system_requirements')
  end

  def browser_upgrade_required
    @log_service.capture_message(view_context.time_stamp('browser_upgrade_required'), 'error_scope')
    render_error_application_requirements t('system_requirements.minimum_settings.browser_upgrade_required')
  end

  def four_oh_four
    @log_service.capture_message(view_context.time_stamp('four_oh_four'), 'error_code')
    render_error_status_code('Page Not Found', '404', t('system_requirements.response_code.four_oh_four'))
  end

  # four_twenty_two, five_hundred :: no custom report needed, they are picked up by the sentry gem
  def four_twenty_two
    render_error_status_code('Application Error', '422', t('system_requirements.response_code.four_twenty_two'))
  end

  def five_hundred
    render_error_status_code('Application Error', '500', t('system_requirements.response_code.five_hundred'))
  end

  private

  def render_error_application_requirements(title)
    @title = title
    render 'errors/application_requirements', layout: 'errors/application_requirements' and return
  end

  def render_error_status_code(title, error_code, error_msg)
    @title = title
    @error_code = error_code
    @error_msg = error_msg
    render 'errors/status_code', layout: 'errors/status_code', status: @error_code and return
  end

  def load_log_service
    @log_service = LogService.new
  end
end

I think your lack of parens around the arguments to your render calls here is confusing you. && has higher precedence than and and the difference is changing how Ruby identifies the arguments to render .

Guessing is no fun though, let's find out for sure. MRI Ruby includes Ripper which allows us to inspect how an expression will be parsed.

require 'ripper'
require 'pp'

and

Ripper.sexp("render 'errors/application_requirements', layout: 'errors/application_requirements' and return")

[:program,
 [[:binary,
   [:command,
    [:@ident, "render", [1, 0]],
    [:args_add_block,
     [[:string_literal,
       [:string_content, [:@tstring_content, "errors/status_code", [1, 8]]]],
      [:bare_assoc_hash,
       [[:assoc_new,
         [:@label, "layout:", [1, 29]],
         [:string_literal,
          [:string_content,
           [:@tstring_content, "errors/status_code", [1, 38]]]]],
        [:assoc_new,
         [:@label, "status:", [1, 59]],
         [:var_ref, [:@ivar, "@error_code", [1, 67]]]]]]],
     false]],
   :and,
   [:return0]]]]

&&

Ripper.sexp("render 'errors/application_requirements', layout: 'errors/application_requirements' && return")

[:program,
 [[:command,
   [:@ident, "render", [1, 0]],
   [:args_add_block,
    [[:string_literal,
      [:string_content, [:@tstring_content, "errors/status_code", [1, 8]]]],
     [:bare_assoc_hash,
      [[:assoc_new,
        [:@label, "layout:", [1, 29]],
        [:string_literal,
         [:string_content,
          [:@tstring_content, "errors/status_code", [1, 38]]]]],
       [:assoc_new,
        [:@label, "status:", [1, 59]],
        [:binary,
         [:var_ref, [:@ivar, "@error_code", [1, 67]]],
         :"&&",
         [:return0]]]]]],
    false]]]]

The output from Ripper isn't the easiest thing to read but if we pay close attention to the indentation of those function call we can see that the and case is calling render(... '..._requirements') and return while the && case is calling render(... '..._requirements' && return) . Those two expressions are going to have very different behaviors.

Like a comment under your Post, indeed you don't need to return here.

However if you still want to use return and have it following RuboCop style, try wrapping render params with brackets.

render('errors/status_code', layout: 'errors/status_code', status: @error_code) && return

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM