When Running Rspec and Sinatra, I keep getting ArgumentError: wrong number of arguments (given 2, expected 0)
When Running Rspec and Sinatra, I keep getting ArgumentError: wrong number of arguments (given 2, expected 0)
我有一个名为 authenticate 的 class 方法,它适用于用户 class。
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 == [=13=]
end
下面是完整的用户 class
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 和 email)?
我需要从 authenticate
获取 id 和 email 方法并将其传递给 initialize
。
我以为这就是我在做的事情,但 Rspec 和 sinatra 都不是这么说的。
提前致谢。
此处您将 id 作为顺序参数传递(在 authenticate
方法中)。
User.new(result[0]['id'], result[0]['email'])
但是您的 User.new
需要关键字参数:
def initialize(id:, email:)
只需这样传递它们:
User.new(id: result[0]['id'], email: result[0]['email'])
此外,我注意到,如果您的 DatabaseConnection.query
return 没有结果,您的 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
这样,如果没有匹配的用户,该方法将 return nil
,并且 post '/sessions'
中的 if user
将正常工作。
我有一个名为 authenticate 的 class 方法,它适用于用户 class。
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 == [=13=]
end
下面是完整的用户 class
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 和 email)?
我需要从 authenticate
获取 id 和 email 方法并将其传递给 initialize
。
我以为这就是我在做的事情,但 Rspec 和 sinatra 都不是这么说的。
提前致谢。
此处您将 id 作为顺序参数传递(在 authenticate
方法中)。
User.new(result[0]['id'], result[0]['email'])
但是您的 User.new
需要关键字参数:
def initialize(id:, email:)
只需这样传递它们:
User.new(id: result[0]['id'], email: result[0]['email'])
此外,我注意到,如果您的 DatabaseConnection.query
return 没有结果,您的 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
这样,如果没有匹配的用户,该方法将 return nil
,并且 post '/sessions'
中的 if user
将正常工作。