Rails种子文件编写遇语法错误与NotNullViolation错误求助
我正在编写生成随机Kudo的Rails种子文件,Kudo包含Title、Content(用Faker生成,这部分没问题),还有giver_id和receiver_id外键,希望在不同用户间随机生成Kudo,但尝试多种写法都出错了:
第一种写法及错误
employees = Employee.create!([{email: Faker::Internet.email(domain: 'gmail.com'), password: 'password'},{email: Faker::Internet.email(domain: 'gmail.com'), password: 'password'},...]) kudos = Kudo.create!(Title: Faker::Adjective.positive, Content: Faker::Company.bs, Kudo.new(giver:Employee.create()), Kudo.new(receiver:Employee.create()))
报错信息:
SyntaxError: /home/valar/Dokumenty/ERP_v1/db/seeds.rb:9: syntax error, unexpected ',', expecting => ...o.new(giver:Employee.create()), Kudo.new(receiver:Employee.c... ... /home/valar/Dokumenty/ERP_v1/db/seeds.rb:9: syntax error, unexpected ')', expecting end-of-input ...ew(receiver:Employee.create()) ... ... ... ^
第二种写法及错误
kudos = Kudo.create!(Title: Faker::Adjective.positive, Content: Faker::Company.bs, giver:Employee.create(), receiver:Employee.create())
报错信息:
rake aborted!
ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR: null value in column "giver_id" violates not-null constraint
模型与Schema信息
Employee模型
class Employee < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :given_kudos, class_name: 'Kudo', foreign_key: 'giver_id' has_many :received_kudos, class_name: 'Kudo', foreign_key: 'receiver_id' end
Kudo模型
class Kudo < ApplicationRecord validates :Title, presence: true validates :Content, presence: true belongs_to :giver, class_name: 'Employee' belongs_to :receiver, class_name: 'Employee' end
Schema文件
ActiveRecord::Schema.define(version: 2023_01_20_162230) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" create_table "employees", 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.index ["email"], name: "index_employees_on_email", unique: true t.index ["reset_password_token"], name: "index_employees_on_reset_password_token", unique: true end create_table "kudos", force: :cascade do |t| t.string "Title", null: false t.text "Content", null: false t.integer "giver_id", null: false t.integer "receiver_id", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end end
修复方案
第一种写法的核心问题是语法错误:create!接收属性哈希,不能直接传入Kudo.new对象;第二种写法的问题是Faker可能生成重复邮箱,导致Employee创建失败,最终giver/receiver为nil,触发非空约束错误。
正确的种子文件写法如下:
# 先创建10个邮箱唯一的员工 employees = [] 10.times do email = Faker::Internet.unique.email(domain: 'gmail.com') employees << Employee.create!(email: email, password: 'password') end # 生成20条Kudo,随机分配给不同员工 20.times do giver = employees.sample # 确保发送者和接收者不是同一人 receiver = employees.reject { |e| e == giver }.sample Kudo.create!( Title: Faker::Adjective.positive, Content: Faker::Company.bs, giver: giver, receiver: receiver ) end
关键说明
- 使用
Faker::Internet.unique.email避免邮箱重复,保证Employee创建成功; - 从已创建的员工池中随机选取giver和receiver,避免动态创建员工时的潜在失败;
- 通过
reject过滤掉发送者自身,符合“不同用户间生成Kudo”的需求。
内容的提问来源于stack exchange,提问作者Wojtek

