为什么设计方法encrypted_pa​​ssword = undefined?

时间:2016-04-21 20:28:45

标签: ruby-on-rails ruby devise

我正在尝试为我的管理模型设置设计。 admin模型继承自Author。我已完成文档中建议的所有设计设置并运行所有迁移等。我的模型如下:

作者类:

class Author < ActiveRecord::Base

  has_many :articles
  validates :first_name, :surname, :email, presence: true
end

管理员类:

class Admin < Author
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable
end

设计迁移:

class DeviseCreateAdmins < ActiveRecord::Migration
  def change
    create_table(:admins) do |t|
    ## Database authenticatable
    t.string :email,              null: false, default: ""
    t.string :encrypted_password, null: false, default: ""

    ## Recoverable
    t.string   :reset_password_token
    t.datetime :reset_password_sent_at

    ## Rememberable
    t.datetime :remember_created_at

    ## Trackable
    t.integer  :sign_in_count, default: 0, null: false
    t.datetime :current_sign_in_at
    t.datetime :last_sign_in_at
    t.inet     :current_sign_in_ip
    t.inet     :last_sign_in_ip

    ## Confirmable
    # t.string   :confirmation_token
    # t.datetime :confirmed_at
    # t.datetime :confirmation_sent_at
    # t.string   :unconfirmed_email # Only if using reconfirmable

    ## Lockable
    # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
    # t.string   :unlock_token # Only if unlock strategy is :email or :both
    # t.datetime :locked_at


    t.timestamps null: false
  end

  add_index :admins, :email,                unique: true
  add_index :admins, :reset_password_token, unique: true
  #add_index :admins, :confirmation_token,   unique: true
  #add_index :admins, :unlock_token,         unique: true
end

在DB中显示encrypted_password的架构。

create_table "admins", force: :cascade do |t|
t.string   "email",                  default: "", null: false
t.string   "encrypted_password",     default: "", null: false
t.string   "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer  "sign_in_count",          default: 0,  null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet     "current_sign_in_ip"
t.inet     "last_sign_in_ip"
t.datetime "created_at",                          null: false
t.datetime "updated_at",                          null: false

尝试在我的某个测试或rails控制台中创建管理员时收到的错误如下:

NoMethodError:
   undefined method `encrypted_password=' for #<Admin:0x007fc1c3269e18>

使用的测试是:

   scenario 'Signing in with correct credentials' do
    Admin.create(first_name: "Jonathan", surname: "Sayer", email: "test@email.com",
              password: "password", password_confirmation: "password")
     visit '/login'
     fill_in 'Email', with: "test@email.com"
     fill_in 'Password', with: "password"
     click_button "Log in"
     expect(page.current_path).to eq root_path
   end

显示错误消息:

1) Signing in  Signing in with correct credentials
 Failure/Error:
   Admin.create(first_name: "Jonathan", surname: "Sayer", email: "test@email.com",
                password: "password", password_confirmation: "password")

 NoMethodError:
   undefined method `encrypted_password=' for #<Admin:0x007fc1c3269e18>
 # /Users/jonathansayer/.rvm/gems/ruby-2.3.0/gems/devise-3.5.6/lib/devise/models/database_authenticatable.rb:43:in `password='
 # ./spec/features/logging_in_and_out_spec.rb:5:in `block (2 levels) in <top (required)>'

任何帮助都将非常感谢!!感谢

1 个答案:

答案 0 :(得分:0)

Solution

Add self.table_name = "admins" to your Admin model to fix the error.

Explanation

I see that the Admin model is inherited from the Author model. Which btw is not recommended unless you are trying to implement STI (single table inheritance). Which is not the case here as you have tables for both the models. And here lies the actual problem.

You see by default ActiveRecord connects a Rails model to it's corresponding table in the DB using the pluralized name of the model.

So in this case for the Author model it corresponds to the authors table in the DB. Now since Admin is inherited from Author it too is connected to authors table.

And that is why all the fields you expect to be present in the admins table is not present. Because right now the Admin model knows only the fields in authors table

The fix would be to explicitly specify the table name for the model.