【问题标题】:ActionView::Template::Error (wrong number of arguments (1 for 2)):ActionView::Template::Error(参数数量错误(1 对 2)):
【发布时间】:2017-08-21 14:31:17
【问题描述】:

我正在开发一个主要基于 Michael Hartl 的 Rails 教程构建的 Rails 应用程序。我在 Logentries 中遇到了一个我无法完全追踪的错误。

ActionView::Template::Error (wrong number of arguments (1 for 2)):
31: <div class="inner">
32: <h1 id="fadeThis" style="display: none;">The Lake County Bar Association</h1>
33:
heroku router - - at=info method=GET path="/" host=www.example.org request_id="REMOVED" fwd="xx.xx.xx.xx" dyno=web.1 connect=1ms service=10ms status=500 bytes=1669 protocol=http
34: <% if logged_in? %>
35: <br>
36: <h2 class="margin-top-0 wow fadeIn" id="welcomeText"> Welcome back, <%= current_user.first_name %>! </h2>
37: <% else %>
app/models/user.rb:46:in `authenticated?'
app/helpers/sessions_helper.rb:11:in `current_user'
app/helpers/sessions_helper.rb:21:in `logged_in?'
app/views/static_pages/home.html.erb:34:in `_app_views_static_pages_home_html_erb__118074299580396133_69921140988760'

这里是经过身份验证的? user.rb 中的方法:

def authenticated?(remember_token)
  return false if remember_digest.nil?
  BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Returns true if the given token matches the digest.
def authenticated?(attribute, token)
  digest = send("#{attribute}_digest")
  return false if digest.nil?
  BCrypt::Password.new(digest).is_password?(token)
end

那么 current_user 和 logged_in 呢? session_helper.rb 中的方法:

def current_user
  if (user_id = session[:user_id])
    @current_user ||= User.find_by(id: user_id)
  elsif (user_id = cookies.signed[:user_id])
    user = User.find_by(id: user_id)
    if user && user.authenticated?(cookies[:remember_token])
      log_in user
      @current_user = user
    end
  end 
end

def logged_in?
  !current_user.nil?
end

还有来自 home.html.erb 的相关部分:

  <% if logged_in? %>
  <br>
  <h2 class="margin-top-0 wow fadeIn" id="welcomeText"> Welcome back, <%= current_user.first_name %>! </h2>
  <% else %>
  <h3> <span class="element"> <br></span></h3>
  <hr>
  <br>

【问题讨论】:

  • 您的 User 模型中似乎有 2 个 def authenticated? 方法,第二个(有 2 个参数)覆盖第一个(只有 1 个参数)
  • 他们不应该都在吗?每种方法的签名略有不同。
  • 这篇文章有助于让你了解正在发生的事情:codedecoder.wordpress.com/2015/04/08/method-overloading-in-ruby
  • 感谢您的链接,我现在看到了。该错误意味着只有一个参数被发送并且它期望接收 2,对吧?
  • 是的,你是对的

标签: ruby-on-rails ruby


【解决方案1】:

Ruby 并不真正支持方法重载。从这个doc

你想用相同的方法创建两个不同版本的方法 名称:两种方法,它们采用的参数不同。然而,一个 Ruby 类只能有一个具有给定名称的方法(如果您定义一个 两次同名方法,以后一种方法定义为准

所以在你的情况下,只有 authenticated?(attribute, token) 被调用

【讨论】:

    【解决方案2】:

    如前所述,Ruby 不支持基于参数的方法重载。为了能够做你想做的事,你可以使用参数、关键字参数或选项哈希。

    我更喜欢关键字参数,因为我在 Python 中看到了很多,并且非常喜欢它的清晰程度。您的偏好或项目偏好可能不同。

    通过参数计数检查方法重载

    def authenticated?(*args)
      case args.count
      when 1
        remember_token = args[0]
        return false if remember_digest.nil?
        BCrypt::Password.new(remember_digest).is_password?(remember_token)
      when 2
        attribute, token = args
        digest = send("#{attribute}_digest")
        return false if digest.nil?
        BCrypt::Password.new(digest).is_password?(token)
      end
    end
    

    调用方法:

    authenticated?(false)
    authenticated?('whatever', 'cool')
    

    您还可以检查参数的类型或使用参数排序(例如authenticated?(nil, nil, true),其中前两个参数是属性和令牌,第三个参数是 remember_token)。

    通过关键字参数重载方法(Ruby 2.0+)

    关键字参数在 Ruby 中使用不足,但它们从 Ruby 2.0 开始可用。

    def authenticated?(remember_token: nil, attribute: nil, token: nil)
      if remember_token
        return false if remember_digest.nil?
        BCrypt::Password.new(remember_digest).is_password?(remember_token)
      elsif attribute && token
        digest = send("#{attribute}_digest")
        return false if digest.nil?
        BCrypt::Password.new(digest).is_password?(token)
      end
    end
    

    调用方法:

    authenticated?(attribute: 'whatever', token: 'cool')
    authenticated?(remember_token: false)
    

    通过选项散列重载方法 (Ruby 1.9)

    在 Ruby 中使用选项散列非常常见的模式/习惯用法:

    def authenticated?(options = {})
      if options['remember_token']
        return false if options['remember_token'].nil?
        BCrypt::Password.new(remember_digest).is_password?(remember_token)
      elsif options['attribute'] && options['token']
        digest = send("#{attribute}_digest")
        return false if digest.nil?
        BCrypt::Password.new(digest).is_password?(token)
      end
    end
    

    调用方法:

    authenticated?(:attribute => 'whatever', :token => 'cool')
    authenticated?(:remember_token => false)
    

    【讨论】:

    • 感谢您如此详细的回复!这对未来的项目非常有用。在这种情况下,我意识到重复的身份验证?方法实际上是一个错误。我删除了一个并更改了方法调用,现在一切都很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2012-02-07
    相关资源
    最近更新 更多