我有一个Rails应用程序,其中有User
模型和Role
模型。
角色可以是超级用户,管理员或用户。
我的用户表迁移如下所示:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :username
t.string :email
t.string :password
t.string :password_digest
t.boolean :banned
t.references :role, foreign_key: true
t.timestamps
end
end
end
每当我使用HTTP POST创建用户时,我都会收到错误:
Role must exist
Rails告诉我,我的用户模型的字段role
不能为空。
所以我想,好吧,我希望通过HTTP POST创建的用户默认为“User”角色,所以我在我的用户模型中有这个:
class User < ApplicationRecord
belongs_to :role
has_secure_password
# validates :role, allow_nil: true
before_validation do
self.banned = false
# Users created through HTTP POST request should always
# default to 'User' role.
# Rails console created users will be explicitly set
# to 'Superuser' or 'Admin' roles.
self.role = Role.find_by({title: 'User'})
puts "User model set role fired!"
end
end
这可以解决错误,但现在我遇到了问题。
当管理员用户尝试将现有用户的角色从“用户”更改为“管理员”时,before_validation
方法始终会触发,永远覆盖我的POST参数以指定用户的新角色。
实际上,我永远无法改变任何用户的角色。
我做错了吗?
当然有一种方法可以创建一个没有在开始时分配任何角色的用户,然后再设置角色......
我几个小时都在摸不着头脑。
我发现了这个:http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
哦,伙计。我忘记了Rails 5 belongs_to
现在已更改为默认情况下需要,需要为我的初始问题设置optional: true
:D
在尝试了Steve的建议之后我的新问题是我的Rails测试给了我错误:
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank
即使我正在进行更新操作而不是创建用户操作。我想知道Bcrypt是否会以某种方式干扰?
当我使用rails console命令生成User模型时,可能只需要password_digest
字段?
需要更多调查......
我想我已经解决了......至少我的所有测试现在都已经过去了,尽管我仍然持怀疑态度:D
我创建了一个新的迁移文件并从Users表中删除了Password列,我的测试仍然通过,包括创建一个新用户。
我仍然可以在rails console --sandbox
我认为其他一些错误是我的用户强大的参数需要将字段从:role
更改为:role_id
。虽然用户模型字段名为role
,但在数据库中,外键实际上是role_id
。
答案 0 :(得分:2)
您可以根据是否已有值来确定作业...
before_validation do
self.banned = false if banned.nil?
self.role ||= Role.find_by(title: 'User')
end
或者你只能在创建....
before_validation do
if new_record?
self.banned = false
self.role = Role.find_by(title: 'User')
end
end
但坦率地说,我通常看到初始默认设置的方式是在控制器的create
方法中
def create
@user = User.assign_attributes(user_params)
@user.banned = false
@user.role = Role.find_by(title: 'User')
if @user.save
# ...
答案 1 :(得分:0)
您只能在创建时使用before_action
:
before_validation :my_action, on: :create