我的意圖是實施STI兩種類型:工作人員和臨牀醫師。我以前的實現是使用枚舉的角色,並在盡我所能按照類似問題的答案後,拿出測試等中的所有引用來枚舉角色並替換爲類型的引用,當我獲得以下錯誤的許多版本運行我的測試套件:單表繼承錯誤 - ActiveRecord :: SubclassNotFound
ERROR["test_valid_signup_information_with_account_activation", UsersSignupTest, 1.01794000000001]
test_valid_signup_information_with_account_activation#UsersSignupTest (1.02s)
ActiveRecord::SubclassNotFound: ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'Staff'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite User.inheritance_column to use another column for that information.
app/controllers/users_controller.rb:19:in `create'
test/integration/users_signup_test.rb:27:in `block (2 levels) in <class:UsersSignupTest>'
test/integration/users_signup_test.rb:26:in `block in <class:UsersSignupTest>'
這裏是我的困惑有可能被隱藏的問題幾個方面:
在我的用戶模型user.rb,我想我正確地確定該子類(工作人員和臨牀醫師),但我不確定是否正確包裝了一切。所有其他代碼是否必須包含在其中一個類中?我濫用「結束」了嗎?
class User < ApplicationRecord
end
class Staff < User
end
class Clinician < User
end
belongs_to :university
has_many :referral_requests
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :type, presence: true
validates :university_id, presence: true, if: lambda { self.type == 'Staff' }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def User.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions.
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
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
# Activates an account.
def activate
update_attribute(:activated, true)
update_attribute(:activated_at, Time.zone.now)
end
# Sends activation email.
def send_activation_email
UserMailer.account_activation(self).deliver_now
end
# Sets the password reset attributes.
def create_reset_digest
self.reset_token = User.new_token
update_attribute(:reset_digest, User.digest(reset_token))
update_attribute(:reset_sent_at, Time.zone.now)
end
# Sends password reset email.
def send_password_reset_email
UserMailer.password_reset(self).deliver_now
end
# Returns true if a password reset has expired.
def password_reset_expired?
reset_sent_at < 2.hours.ago
end
def feed
ReferralRequest.where("user_id = ?", id)
end
private
# Converts email to all lower-case.
def downcase_email
self.email = email.downcase
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
下面是發生故障的具體測試代碼(許多被失敗的測試套件之一 - 所有的用戶參數也同樣,雖然定義)。我是否適當地傳遞員工參數?
test "valid signup information with account activation" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { name: "Example User",
email: "[email protected]",
university_id: 1 ,
type: "Staff",
password: "password",
password_confirmation: "password" } }
這裏是我的用戶表的模式:
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.datetime "reset_sent_at"
t.integer "university_id"
t.integer "role"
t.string "type"
t.index ["email"], name: "index_users_on_email", unique: true
end
非常感謝您的任何想法!我在這裏問了很多問題,但只是在嘗試通過相似的答案很長一段時間之後。
的代碼示例是正確的,只要是我怎麼把它寫在。根據您的有用反饋,這顯然是錯誤的。我會執行。謝謝! – mike9182
一個問題:爲什麼我需要將切換到STI的方法(如摘要)更改爲新的語法?我相信你,我可以這樣寫,但我不知道它爲什麼會改變。 – mike9182
@ mike9182與STI無關,這就是Rubyists如何寫的。我認爲你的工作有效,但我給出的例子是其他Ruby用戶期望看到的。 –