Ruby-on-rails 使用 rspec 获取“ActiveRecord::UnknownAttributeError: unknown attribute: email_confirmation”错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16050686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting "ActiveRecord::UnknownAttributeError: unknown attribute: email_confirmation" Error with rspec
提问by josephndenton
I am running into this error when running my tests. I have checked to make sure all the email_confirmations are spelled correctly and (unless I am crazy) they are. I'm a bit of a Rails noob, so it could be something simple.
我在运行测试时遇到了这个错误。我已经检查以确保所有email_confirmations 拼写正确,并且(除非我疯了)它们是。我是一个 Rails 菜鸟,所以它可能很简单。
User Model
用户模型
class User < ActiveRecord::Base
attr_accessible :email, :email_confirmation, :first_name, :last_name,
:password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
validates :first_name, presence: true, length: { maximum: 25 }
validates :last_name, presence: true, length: { maximum: 25 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :email_confirmation, presence: true
validates :password, presence: true, length: { maximum: 6 }
validates :password_confirmation, presence: true
end
Rspec tests
Rspec 测试
require 'spec_helper'
describe User do
before { @user = User.new(email: "[email protected]",
first_name: "John", last_name: "Smith",
password: "foobar", password_confirmation: "foobar",
email_confirmation: "[email protected]") }
subject { @user }
it { should respond_to(:first_name) }
it { should respond_to(:last_name) }
it { should respond_to(:email) }
it { should respond_to(:email_confirmation) }
it { should respond_to(:password_digest) }
it { should respond_to(:password) }
it { should respond_to(:password_confirmation) }
it { should respond_to(:authenticate) }
it { should be_valid }
describe "when first name is not present" do
before { @user.first_name = " " }
it { should_not be_valid }
end
describe "when last name is not present" do
before { @user.last_name = " " }
it { should_not be_valid }
end
describe "when email is not present" do
before { @user.email = @user.email_confirmation = " " }
it { should_not be_valid }
end
describe "when password is not present" do
before { @user.password = @user.password_confirmation = " " }
it { should_not be_valid }
end
describe "when first_name is too long" do
before { @user.first_name = "a" * 26 }
it { should_not be_valid }
end
describe "when last_name is too long" do
before { @user.last_name = "a" * 26 }
it { should_not be_valid }
end
describe "when email format is invalid" do
it "should be invalid" do
addresses = %w[user@foo,com user_at_foo.org example.user@foo.
foo@bar_baz.com foo@bar+baz.com]
addresses.each do |invalid_address|
@user.email = invalid_address
@user.should_not be_valid
end
end
end
describe "when email format is valid" do
it "should be valid" do
addresses = %w[[email protected] [email protected] [email protected] [email protected]]
addresses.each do |valid_address|
@user.email = valid_address
@user.should be_valid
end
end
end
describe "when email address is already taken" do
before do
user_with_same_email = @user.dup
user_with_same_email.email = @user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
describe "when password doesn't match confirmation" do
before { @user.password_confirmation = "mismatch" }
it { should_not be_valid }
end
describe "when email doesn't match confirmation" do
before { @user.email_confirmation = "[email protected]" }
it { should_not be_valid }
end
describe "when password confirmation is nil" do
before { @user.password_confirmation = nil }
it { should_not be_valid }
end
describe "when email confirmation is nil" do
before { @user.email_confirmation = nil }
it { should_not be_valid }
end
describe "with a password that's too short" do
before { @user.password = @user.password_confirmation = "a" * 5 }
it { should be_invalid }
end
describe "return value of authenticate method" do
before { @user.save }
let(:found_user) { User.find_by_email(@user.email) }
describe "with valid password" do
it { should == found_user.authenticate(@user.password) }
end
describe "with invalid password" do
let(:user_for_invalid_password) { found_user.authenticate("invalid") }
it { should_not == user_for_invalid_password }
specify { user_for_invalid_password.should be_false }
end
end
end
schema.rb
模式文件
ActiveRecord::Schema.define(:version => 20130417021135) do
create_table "users", :force => true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "password_digest"
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
end
回答by Stuart M
You're getting UnknownAttributeErrorbecause you don't have a column in your userstable called email_confirmation. By default, ActiveRecord will look for DB columns named the same as the attributes you use to construct the model, but this line is trying to construct a User with an attribute the database doesn't know about:
你得到的UnknownAttributeError是因为你的users表中没有名为email_confirmation. 默认情况下,ActiveRecord 将查找与您用于构建模型的属性名称相同的 DB 列,但此行尝试使用数据库不知道的属性构建用户:
before { @user = User.new(email: "[email protected]",
first_name: "John", last_name: "Smith",
password: "foobar", password_confirmation: "foobar",
email_confirmation: "[email protected]") }
Are you really intending to save the email confirmation in the database, or are you just wanting to check that it matches email before saving it? I assume the latter, and Rails actually has built-in support for doing just that:
您真的打算将电子邮件确认保存在数据库中,还是只想在保存之前检查它是否与电子邮件匹配?我假设是后者,而且 Rails 实际上已经内置支持这样做:
class User < ActiveRecord::Base
validates :email, :confirmation => true
validates :email_confirmation, :presence => true
end
See more details on the Rails Guide to Validations, or the validates_confirmation_ofAPI docs. (And you'll probably need to do the same thing for :password_confirmation.)
请参阅Rails Guide to Validations或validates_confirmation_ofAPI 文档的更多详细信息。(而且您可能需要对 . 做同样的事情:password_confirmation。)
回答by agarcher
Having just spent a ton of time debugging my own instance of this, I thought I would chime in with a third possibility.
刚刚花了大量时间调试我自己的这个实例,我想我会加入第三种可能性。
I had done a migration correctly and verified it by inspecting my ActiveRecordin the rails console. I had tried recreating my db from the schema many times and I had tried re-running the migration many times, all to no avail.
我已经正确地完成了迁移,并通过ActiveRecord在 rails 控制台中检查我的来验证它。我曾多次尝试从架构中重新创建我的数据库,并且多次尝试重新运行迁移,但都无济于事。
The problem, in my case, is that I was seeing the problem when running my unit tests, not at runtime. The issue is that my test database had gotten out of sync in my migration/rollback testing. The solution was quite simple. All I had to do was reset the test database with:
就我而言,问题是我在运行单元测试时看到了问题,而不是在运行时。问题是我的测试数据库在我的迁移/回滚测试中不同步。解决方法很简单。我所要做的就是使用以下命令重置测试数据库:
rake db:test:prepare
回答by Donato
I understand that the answer above is marked correct and solves the OP's problem. But there is another cause for this error that goes unheeded in a number of stackoverflow posts on this topic. This error can occur in a polymorphic many to many when you forget to use the as: option to a has_many. For example:
我知道上面的答案被标记为正确并解决了 OP 的问题。但是,此错误的另一个原因在有关此主题的许多 stackoverflow 帖子中都没有引起注意。当您忘记对 has_many 使用 as: 选项时,此错误可能发生在多态多态中。例如:
class AProfile < ActiveRecord::Base
has_many :profile_students
has_many :students, through: :profile_students
end
class BProfile < ActiveRecord::Base
has_many :profile_students
has_many :students, through: :profile_students
end
class ProfileStudent < ActiveRecord::Base
belongs_to :profile, polymorphic: :true
belongs_to :student
end
class Student < ActiveRecord::Base
has_many :profile_students
has_many :aprofiles, through: :profile_students
has_many :bprofiles, through: :profile_students
end
This will give you this error:
这会给你这个错误:
Getting “ActiveRecord::UnknownAttributeError: unknown attribute: profile_id
when you try to do the following:
当您尝试执行以下操作时:
a = AProfile.new
a.students << Student.new
The solution is to add the :as option to AProfile and BProfile:
解决方案是在 AProfile 和 BProfile 中添加 :as 选项:
class AProfile < ActiveRecord::Base
has_many :profile_students, as: :profile
has_many :students, through: :profile_students
end
class BProfile < ActiveRecord::Base
has_many :profile_students, as: :profile
has_many :students, through: :profile_students
end
回答by koios
I had the same issue and this worked like magic. Add this line at the end of your migration statements for each model you would update. Resets all the cached information about columns, which will cause them to be reloaded on the next request.
我有同样的问题,这就像魔法一样。在您要更新的每个模型的迁移语句的末尾添加此行。重置有关列的所有缓存信息,这将导致它们在下一个请求时重新加载。
<ModelName>.reset_column_information
Reference : https://apidock.com/rails/ActiveRecord/Base/reset_column_information/class
参考:https: //apidock.com/rails/ActiveRecord/Base/reset_column_information/class
回答by Hero
I have the same message error and I fix ordering the params as same order of columns definition in database:
我有相同的消息错误,我修复了对参数的排序与数据库中列定义的相同顺序:
CONTROLLER
控制器
def create
worktime = Worktime.create(name: params[:name], workhours: params[:workhours], organization: @organization, workdays: params[:workdays])
render json: worktime
end
DATABASE
数据库
Table: worktimes
Columns:
id int(11) AI PK
name varchar(255)
workhours text
organization_id int(11)
workdays text

