2017-08-05 39 views
0

私の意図は、スタッフと臨床家の2種類で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 

ここで失敗している特定のテストコード( - すべてのユーザーパラメータが同様にかかわらず定義されて失敗しているテストスイートの多くのもの)です。 staffパラメーターを適切に渡していますか?任意のアイデアを

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 

どうもありがとうございました:

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" } } 

は、ここに私のユーザーテーブルスキーマです!私はここで多くの質問をしますが、それはかなりの間、同様の回答を処理しようとした後です。

答えて

1

上記のコードサンプルが正確であると仮定すると、user.rbファイルは無効なRubyであり、解析に失敗しているため、このエラーが表示されます。あなたはまた、それについての通訳のエラーを見ているべきです。

class User < ApplicationRecord 
    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 

    has_secure_password 
    validates :password, presence: true, length: { minimum: 6 }, allow_nil: true 
    # etc... 
end 

class Staff < User 
    validates :university_id, presence: true 
end 

class Clinician < User 
end 

標準クラス継承慣行が適用され、従ってコードがそこに存在する場合、それはそれが移動すべき特定のサブクラス(例えばuniversity_id検証がStaffへの移動)に対してのみ適切です。

# 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 

これらは

def self.digest(string) 
    # ... 
end 

def self.new_token 
    # ... 
end 

または、代わりのように記述しなければならないことは、私はそれが書かれていた方法ですと、

class << self 
    def digest(string) 
    # ... 
    end 

    def new_token 
    # ... 
    end 
end 
+0

コードサンプルは、右限りです。あなたの有益なフィードバックに基づいて明らかに間違っています。私は実装します。ありがとう! – mike9182

+0

1つの質問:STIへの切り替えで新しい構文に消化するなどの方法を変更する必要があるのはなぜですか?私はあなたを信じています。私はそれを確かに書くことができますが、なぜそれが変わったのか分かりません。 – mike9182

+0

@ mike9182はSTIとは関係がありません。それはRubyの書いたとおりです。私はあなたが働いていると思っていますが、私が与えた例は、他のRubyの人々が期待するものです。 –

関連する問題