播种数据库时类型不匹配

Type mismatch when seeding database

我正在尝试为应用程序数据库播种,但出现以下错误:

ActiveRecord::AssociationTypeMismatch: Role(#97332160) expected,
got Fixnum(#76482890)

这里是我的schema.rb关于两个table问题的部分:

create_table "roles", force: :cascade do |t|
  t.string   "role",       limit: 50, null: false
  t.datetime "created_at",            null: false
  t.datetime "updated_at",            null: false
end

create_table "users", force: :cascade do |t|
  t.string   "first_name", limit: 100, null: false
  t.string   "surname",    limit: 100, null: false
  t.string   "email",      limit: 255
  t.integer  "role_id",    limit: 11
  t.string   "password",   limit: 150
  t.datetime "created_at",             null: false
  t.datetime "updated_at",             null: false
end

add_index "users", ["first_name"], name: "index_users_on_first_name", using: :btree
add_index "users", ["role_id"], name: "index_users_on_role_id", using: :btree
add_index "users", ["surname"], name: "index_users_on_surname", using: :btree

add_foreign_key "users", "roles"

这是我的 seeds.rb 命令:

rl = Role.create(role: "root")
User.create(first_name: "Edvaldo", surname: "Silva de Almeida Júnior", email: "edvaldo@my.domain.com", role_id: rl.id, password: "my_password")

rl = Role.create(role: "admin")
User.create(first_name: "Daiely", surname: "Fanchin", email: "daiely@my.domain.com", role_id: rl.id, password: "other_password")

rl = Role.create(role: "user")
User.create(first_name: "César", surname: "Silva", email: "cesar@my.domain.com", role_id: rl.id, password: "yet_other_password")

我发现 a question 接受的答案建议我应该这样做:

rl = Role.create(role: "root")
User.create(first_name: "Edvaldo", surname: "Silva de Almeida Júnior", email: "edvaldo@my.domain.com", role_id: Role.find(rl.id), password: "my_password")

我试过了,但得到了同样的错误!此外,我使用 role_id 作为关联,而不是角色本身。因此,就我而言,它应该收到 Fixnum,而不是 Role

add_foreign_key "users", "roles" 这将为用户添加 role_id 列,无需单独编写 t.integer "role_id", limit: 11

应该有一些联想

  class User < ActiveRecord::Base
    belongs_to :role
  end 

create_table "users", force: :cascade do |t|
  t.string   "first_name", limit: 100, null: false
  t.string   "surname",    limit: 100, null: false
  t.string   "email",      limit: 255
  t.reference "role",      index: true
  t.string   "password",   limit: 150
  t.datetime "created_at",             null: false
  t.datetime "updated_at",             null: false
end


add_foreign_key "users", "roles", column: :role_id

希望它能解决它。

我在我的用户模型中添加了一个方法 set_default_role

class User < ActiveRecord::Base
  has_one :role
  after_initialize :set_default_role, :if => :new_record?

  def set_default_role
    if User.count == 0
      self.role ||= 1
    else
      self.role ||= 2
    end
  end

end

但是这个方法是错误的,我一改写就

def set_default_role
  if User.count == 0
    self.role_id ||= 1
  else
    self.role_id ||= 2
  end
end

我的播种效果很好。

所以,问题是我尝试(在此方法内)将 Role 设置为 Fixnum。

这是对 Rails 新手的 建议 播种不仅仅是将某些内容强加到您的数据库中。这是对您的模型的全面评估,有时错误可能是由某些方法的执行引起的,而不仅仅是您尝试加载的值。

你的问题很简单:

role_id: Role.find(rl.id)

.find() returns 一个 Role 对象。

您的 create 方法需要 foreign_key(整数)(role_id: [int])。

简单的修复方法是:

 User.create(... role_id: Role.find(rl.id).id ...)

.. 或 ...

     User.create(... role_id: rl.id ...)

...甚至更好...

 User.create(... role: rl ...)

--

修复

真正的解决方法是 在您的数据库中设置 default,或者像您在提交的答案中那样手动设置 role_id

我强烈建议使用数据库 default,因为那样的话,您的应用程序中发生的事情并不重要 - 您的数据库将始终 "default" 到您设置的角色:

$ rails g migration SetDefaultForRole

$ db/migrate/set_default_for_role_____.rb
class SetDefaultForRole < ActiveRecord::Migration
   def change
      change_column :users, :role_id, :integer, default: 0
   end
end

$ rake db:migrate

这样做的缺点是将设置此整数默认值(除非您再次更改数据库)。虽然这本身不是问题,但它会为您的 Role 模型创建一个 antipattern(IE,您可以创建任何角色,只要它是 初始角色之后你做了)。

--

另一种方法是为用户设置 Role

你已经有了这个;你可以清理它:

#app/models/user.rb
class User < ActiveRecord::Base
   before_create :set_role, if: Proc.new { |m| m.role_id.blank? }

   private

   def set_role
     self.role_id = "1" if User.count == 0
   end
end