rails/ruby "и вернуть false"

Я видел этот код в учебнике по рельсам, который я делаю

def access_denied
  redirect_to login_path, :notice => "Please log in to continue" and return false
end

Прежде чем изучать рельсы, я сделал большое количество исследований рубинов, и ни одна из прочитанных мной книг не охватывала этот "синтаксис" и "возвращает ложный". Я не могу найти упоминания об этом в синтаксисе rails, может ли кто-нибудь предоставить ссылку или какое-либо объяснение, которое прояснит это?

Я не понимаю необходимость "и" здесь, поскольку я думал, что ruby всегда будет возвращать последнее оцениваемое выражение.

Ответ 1

И есть только для вас, чтобы иметь возможность написать возвращение ложного в той же строке, что и предыдущее выражение.

Это эквивалентно этому:

redirect_to login_path, :notice => "Please log in to continue"
return false

это не совсем то же самое, потому что с "и" оно вернет false только в том случае, если метод redirect_to возвращает то, что не является нильским или ложным, но поскольку оно почти всегда возвращает то, что не является нилным или ложным, то правая часть утверждения всегда выполняется (и возвращается false).

В Ruby и Ruby это просто псевдоним && и ведет себя точно так же, как и с одним отличием, он имеет более низкий приоритет, чем все остальные части выражения, поэтому сначала он оценивает все, что на нем слева, а затем применяется. Ruby также имеет или который совпадает с || но с более низким приоритетом в выражениях.

Ответ 2

redirect_to login_path, :notice => "Please log in to continue" - это нормальное выражение в Ruby, которое не возвращает false (или nil, см. исходный код), поэтому выполнение программы продолжается (чтобы проверить вторую часть после AND) и return false может быть выполнено.

Ответ 3

Такая конструкция использовалась с фильтром, когда ожидались значения возврата фильтра. false остановит обычную обработку запроса.

Поэтому, если контроллер выглядит так:

class FooController < ActionController::Base
  before_filter :access_denied
  # etc.
end

Ни одно из действий контроллера не будет работать; этот метод, вероятно, предназначен для вызова из фильтра, например:

def check_access
  return access_denied unless current_user.has_access
end

В эти дни значения возврата фильтра игнорируются.

Он может использоваться как обычный метод в действии, чтобы прекратить обработку действия и вернуть после перенаправления, поэтому никакой другой логики/рендеринга /etc. запускается внутри контроллера.

Ответ 4

Документация по операторам: в разделе "Определено?" И "Или" и "Нет"

Использование and полезно для объединения связанных операций вместе, пока один из них не возвращает nil или false. Вы можете использовать его, как вы показали в своем вопросе, или вы также можете использовать его для короткого замыкания строки кода.

# Short circuit example
blog = Blog.find_by_id(id) and blog.publish! 

Блог только получает .publish! вызвал его, если find_by_id был успешным.

В вашем примере:

def access_denied
  redirect_to login_path, :notice => "Please log in to continue" and return false
end

Они просто используют его для записи кода более компактно на одной строке.

Тем не менее, он также полезен для действия контроллера, где вы можете выполнять рендеринг на основе условных выражений, и вы не хотите получать предупреждения Rails "multiple Renders":

def show
  if something
    render :partial => 'some_partial'
  end

  render :partial => 'some_other_partial'
end

Rails даст вам предупреждение, если something вернет true, так как в действии есть несколько выражений рендеринга. Однако, если вы изменили его на

if something
  render :partial => 'some_partial' and return
end

это позволит вам остановить выполнение действия.