Ruby 中的方法定义和命名约定

Method definition and naming conventions in Ruby

我主要来自 C# 背景,目前我在 Rails 上学习 Ruby。通读 railstutorial.org,我看到很多这样的代码(这个是代码清单 10.49):

class PasswordResetsController < ApplicationController
  before_action :get_user,   only: [:edit, :update]
  before_action :valid_user, only: [:edit, :update]
  .
  .
  .
  def edit
  end

  private

    def get_user
      @user = User.find_by(email: params[:email])
    end

    # Confirms a valid user.
    def valid_user
      unless (@user && @user.activated? &&
              @user.authenticated?(:reset, params[:id]))
        redirect_to root_url
      end
    end
end

现在,我学到的是让方法尽可能细化,方法名称尽可能提供信息。这里的方法 valid_user 检查用户是否有效,如果无效则重定向到 root_url

在这种情况下,我要做的是将方法重命名为 redirect_to_root_if_not_valid,或者不使用单独的方法,如果需要检查,只需使用 user.valid? 之类的方法,并且然后在需要的地方重定向。

对我来说,方法名称和方法信息具有误导性,它不仅确认有效用户,如果用户无效,它还会重定向到某个地方。

这对我来说是不是很奇怪,因为我来自 C# 背景,还是这只是我不习惯的另一种做事方式?

我认为这些方法的命名很糟糕。首先,我会将 activated? 的检查拉入 User class 的保护子句中,因为非活动用户可以 never 进行身份验证在我看来:

class User < ActiveRevord::Base
  # ...

  def authenticated?(...)
    return false unless activated?
    # ...
  end
end

然后,我将方法重命名为 assign_userensure_user_authenticated,将身份验证检查提取到一个单独的方法中,并使用 @obj.try(:method, args) 而不是 @obj && @obj.method(args)控制器:

class PasswordResetsController < ApplicationController
  before_action :assign_user, only: [:edit, :update]
  before_action :ensure_user_authenticated, only: [:edit, :update]

  # ...

  private

    def assign_user
      @user = User.find_by(email: params[:email])
    end

    def ensure_user_authenticated
      redirect_to root_url unless user_authenticated?
    end

    def user_authenticated?
      @user.try(:authenticated?, :reset, params[:id])
    end
end

您正在进入 "what's the best way to do x" 的恐怖谷,ruby 社区的人们喜欢这样。不管怎样,我将再提供一个关于如何重构代码的意见

创建一个 authenticated? 和过滤方法 [并将它们放在 ApplicationController 中,您可能会重用它 |与否,这取决于逻辑是否可共享]。此外,我喜欢定义一个 user 方法和编写器,而不是使用过滤器来实现 [几乎] 相同的行为。

class ApplicationControlller < ActionController::Base
  before_action :restrict_access_to_authenticated_users

  private

  def restrict_access_to_authenticated_users
    redirect_to root_path unless authenticated?
  end

  def authenticated?(u = user)
    u && u.activated? && u.authenticated?(:reset, params[:id])
  end

  attr_writer :user # I use this so you can overwrite the user without using the code beneath
  def user
    @user ||= User.find_by_email(params[:email])
  end
end