基于角色的条件模型验证

时间:2017-08-01 16:55:06

标签: ruby-on-rails

我在用户模型中使用枚举实现的用户具有角色:

enum role: [:staff, :clinician]

我有一个大学模型,用户为belongs_to:university,大学模型为has_many:users。

我的应用程序的工作方式是"员工"将属于大学,但"临床医生"是私人执业,因此不需要属于大学,也不需要在注册期间选择一个。

如果用户选择了临床医生,我的注册表单设置为隐藏大学字段,但我想确保我的验证设置为要求任何选择注册人员的用户也必须选择一所大学任何在注册时选择临床医生的用户如果选择了大学,将无法通过验证。

以下是用户注册表单的角色部分:

<%= f.label :role %>
      <%= f.select(:role, User.roles.keys.map {|role| [role.titleize,role]}, :include_blank => "Please Select", id: 'user_role')  %>

      <%= content_tag :div, class: 'js-dependent-fields', data: { 'select-id': 'user_role', 'option-value': 'staff'} do %>
      <%= f.label :university_id%>
      <%= collection_select( :user, :university_id, University.all, :id, :name, prompt: true) %>

2 个答案:

答案 0 :(得分:2)

它需要更多的额外设置,但我认为随着时间的推移,灵活性会得到回报:

尝试将单表继承与您的枚举角色结合使用。您将能够更轻松地为不同角色定义单独的回调,验证,范围和关联,同时继承您希望它们共享的共享。例如,您只能将其设为Staff belongs_to :university,而Clinician则不会。

# Stripped down schema

create_table "universities", force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

create_table "users", force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.bigint "university_id"
  t.integer "role"
  t.index ["university_id"], name: "index_users_on_university_id"
end

# Models

class University < ApplicationRecord
  has_many :staffs
end

class User < ApplicationRecord
  self.inheritance_column = :role
  enum role: { Staff: 0, Clinician: 1 }
end

class Clinician < User
end

class Staff < User
  belongs_to :university
end

Staff.first.university # => returns instance of University
Clinician.first.university # => raises NoMethodError
University.first.staffs # => returns collection of Staff objects
University.first.clinicians # => raises NoMethodError

请注意,没有type列。通过设置role:integer,它被enum用于self.inheritance_column = :role的列覆盖了。您可以使用字符串/符号表示与enum角色进行互动("Staff"Staff.newUser.first.Staff?User.first.Staff!User.new(role: "Staff")和ActiveRecord小心地将该字符串转换为数据库查询的正整数。

例如,这是User.where(role: "Staff")

的查询
SELECT  "users".* FROM "users" WHERE "users"."role" = 0

Staff.all返回相同的结果,但查询的措辞略有不同

SELECT  "users".* FROM "users" WHERE "users"."role" IN (0)

有关详细信息,请参阅此问题:Same Model with different columns Rails

答案 1 :(得分:1)

您可以为User.rb模型中的validates电话提供条件:

validates :university, presence: true, if: lambda { self.role.to_s == 'staff' }
# watch out for symbol vs. string in your self.role array

我认为(从未这样做过但我想这会有用)你可以为:clinician角色做到这一点:

validates :university, presence: false, if: lambda { self.role.to_s == 'clinician' }