【问题标题】:When Running Rspec and Sinatra, I keep getting ArgumentError: wrong number of arguments (given 2, expected 0)运行 Rspec 和 Sinatra 时,我不断收到 ArgumentError: wrong number of arguments (given 2, expected 0)
【发布时间】:2019-05-10 22:57:32
【问题描述】:

我有一个名为 authenticate 的类方法,它适用于 User 类。

def self.authenticate(email:, password:)
  result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")

  User.new(result[0]['id'], result[0]['email'])
end

我有一个 Rspec 测试;

feature 'authentication' do
  it 'a user can sign in' do
    User.create(email: 'test@example.com', password: 'password123')

    visit 'sessions/new'
    fill_in(:email, with: 'test@example.com')
    fill_in(:password, with: 'password123')
    click_button 'Sign In'

    expect(page).to have_content 'Welcome, test@example.com'
  end
end

运行 Rspec 时,出现以下错误;

1) authentication a user can sign in
     Failure/Error:
       def initialize(id:, email:)
         @id = id
         @email = email
       end

     ArgumentError:
       wrong number of arguments (given 2, expected 0)
     # ./lib/user.rb:15:in `initialize'
     # ./lib/user.rb:23:in `new'
     # ./lib/user.rb:23:in `authenticate'
     # ./app.rb:84:in `block in <class:BookmarkManager>'

下面是我的 Sinatra 应用程序;

require 'sinatra/base'
require './lib/bookmark'
require './lib/user'
require './database_connection_setup.rb'
require 'uri'
require 'sinatra/flash'
require_relative './lib/tag'
require_relative './lib/bookmark_tag'

class BookmarkManager < Sinatra::Base
  enable :sessions, :method_override
  register Sinatra::Flash

  get '/' do
    "Bookmark Manager"
  end
  get '/bookmarks' do
    @user = User.find(session[:user_id])
    @bookmarks = Bookmark.all
    erb :'bookmarks/index'
  end

  post '/bookmarks' do
    flash[:notice] = "You must submit a valid URL" unless     Bookmark.create(url: params[:url], title: params[:title])

    redirect '/bookmarks'
  end

  get '/bookmarks/new' do
    erb :'bookmarks/new'
  end

  delete '/bookmarks/:id' do
    Bookmark.delete(id: params[:id])
    redirect '/bookmarks'
  end

  patch '/bookmarks/:id' do
    Bookmark.update(id: params[:id], title: params[:title], url: params[:url])
    redirect('/bookmarks')
  end

  get '/bookmarks/:id/edit' do
    @bookmark = Bookmark.find(id: params[:id])
    erb :'bookmarks/edit'
  end

  get '/bookmarks/:id/comments/new' do
    @bookmark_id = params[:id]
    erb :'comments/new'
  end

  post '/bookmarks/:id/comments' do
    Comment.create(text: params[:comment], bookmark_id: params[:id])
    redirect '/bookmarks'
  end

  get '/bookmarks/:id/tags/new' do
    @bookmark_id = params[:id]
    erb :'/tags/new'
  end

  post '/bookmarks:id/tags' do
    tag = Tag.create(content: params[:tag])
    BookmarkTag.create(bookmark_id: params[:id], tag_id: tag.id)
    redirect '/bookmarks'
  end

  get '/users/new' do
    erb :'users/new'
  end

  post '/users' do
    user = User.create(email: params[:email], password: params[:password])
    session[:user_id] = user.id
    redirect '/bookmarks'
  end

  get '/sessions/new' do
    erb :'sessions/new'
  end

  post '/sessions' do
    user = User.authenticate(email: params[:email], password: params[:password])
    if user
      session[:user_id] = user.id
      redirect('/bookmarks')
    else
      flash[:notice] = 'Please check your email or password.'
      redirect('/sessions/new')
    end
  end

  run! if app_file == $0
end

下面是完整的用户类

require_relative './database_connection'
require 'bcrypt'

class User
  def self.create(email:, password:)
    encypted_password = BCrypt::Password.create(password
    )
    result = DatabaseConnection.query("INSERT INTO users (email, password) VALUES('#{email}', '#{encypted_password}') RETURNING id, email;")

    User.new(id: result[0]['id'], email: result[0]['email'])
  end

  attr_reader :id, :email

  def initialize(id:, email:)
    @id = id
    @email = email
  end

  def self.authenticate(email:, password:)
    result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'")

    User.new(result[0]['id'], result[0]['email'])
  end

  def self.find(id)
    return nil unless id
    result = DatabaseConnection.query("SELECT * FROM users WHERE id = #{id}")
    User.new(
      id: result[0]['id'],
      email: result[0]['email'])
  end
end

我不明白的是,为什么 Rspec 说它期待 0 个参数,而 initialize 方法显然需要两个参数(id 和电子邮件)? 我需要从authenticate 获取id 和email 方法并将其发送到initialize。 我以为这就是我在做的事情,但 Rspec 和 sinatra 都不是这么说的。

谢谢,提前。

【问题讨论】:

    标签: ruby sinatra rspec2 argument-error


    【解决方案1】:

    在这里,您将 id 作为顺序参数传递(在 authenticate 方法中)。

    User.new(result[0]['id'], result[0]['email'])
    

    但是您的 User.new 需要关键字 args:

    def initialize(id:, email:)
    

    只需这样传递它们:

    User.new(id: result[0]['id'], email: result[0]['email'])
    

    另外,我注意到了一点,如果你的DatabaseConnection.query 没有返回结果,你的authenticate 会从result[0]['id'] 引发一个错误(它会说"Undefined method [] for Nil:NilClass"。也许你应该解决这个问题并为它添加一个测试用例,例如:

    def self.authenticate(email:, password:)
      result = DatabaseConnection.query(
        "SELECT * FROM users WHERE email = '#{email}'"
      )
      record = result[0]
      if record
        User.new(id: result[0]['id'], email: result[0]['email'])
      end
    end
    

    这样,如果没有匹配的用户,该方法将返回nil,并且post '/sessions' 中的if user 将正常工作。

    【讨论】:

    • 感谢您的帮助。您对关键字 args 的看法是正确的。它还解决了我遇到的另一个 Rspec 错误。至于不返回结果,我已经用下面的代码def self.authenticate(email:, password:) result = DatabaseConnection.query("SELECT * FROM users WHERE email = '#{email}'") return unless result.any? return unless BCrypt::Password.new(result[0]['password']) == password User.new(id: result[0]['id'], email: result[0]['email']) end
    • 是的......也可能值得考虑使用像 datamapper 或 activerecord 这样的 ORM......他们在那里帮助不伤害:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 2013-12-12
    相关资源
    最近更新 更多