RoR 4 belongs_to foreign_key未选中

时间:2015-10-25 10:14:06

标签: ruby-on-rails activerecord rails-activerecord

我是RoR的新手,我正在尝试做一个简单的实验。我想要一个用户模型和一个角色模型。每个用户只有一个角色,但单个角色可能会引用多个用户。

所以,这是我的模特:

class Role < ActiveRecord::Base
  has_many :user
end

class User < ActiveRecord::Base
  has_one :role
end

以下是迁移:

class CreateRoles < ActiveRecord::Migration
  def change
    create_table :roles do |t|
      t.string :name, null: false, index: true, unique: true, limit: 16
      t.integer :permissions, null: false
    end
  end
end

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email, null: false, index: true,  unique: true, limit: 128
      t.string :password_digest, null: false, limit: 40
      t.string :password_salt, null: false, limit: 40
      t.string :screen_name, default: '', limit: 32
      t.belongs_to :role, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

我想要的是当我尝试将用户与不存在的角色连接时引发异常:

user = User.create(email: 'user@example.com', password_digest: 'pwd_dig',
                   password_salt: 'salt', role_id: 10)

不幸的是,无论id 10的角色是否存在,都可以创建新用户。

那么,我如何在这里强制执行foreign_key检查?

还有一个问题。如果我尝试这样做:

user = User.create(email: 'user@example.com', password_digest: 'pwd_dig',
                   password_salt: 'salt', role: role)

它引发了异常,因为role没有属性user_id。没有办法这样做,是吗?

3 个答案:

答案 0 :(得分:2)

  

我是RoR的新手

欢迎!!

http://10.0.2.2/idiomjson/insertnew.php

这将允许您进行以下操作:

#app/models/role.rb
class Role < ActiveRecord::Base
   has_many :users
end

#app/models/user.rb
class User < ActiveRecord::Base
   belongs_to :role

   validates :role_id, presence: true, on: :create
   validate :check_role, on: :create

   private

   def check_role
      errors.add(:role_id, "Role doesn't exist") unless Role.exists? role_id
   end
end

因为你是新人,我会给你一些信息:

<强> 1。协会

您的关联有点不正确 - 您最好使用belongs_to/has_many relationship

enter image description here

#app/controllers/users_controller.rb class UsersController < ApplicationController def new @user = User.new @roles = Role.all end def create @user = User.new user_params @user.save end private def user_params params.require(:user).permit(:email, :etc, :role) end end #app/views/users/new.html.erb <%= form_for @user do |f| %> <%= f.email_field :email %> <%= f.collection_select :role_id, @roles, :id, :name %> <%= f.submit %> <% end %> 会在belongs_to模型中分配foreign_key,允许您引用并验证它。

-

<强> 2。 Custom validator

其次,您将能够使用验证来检查User是否已正确设置。

每次保存Rails模型时,它都会调用您设置的一系列验证器 - 允许您调用检查角色是否存在等功能。

答案 1 :(得分:2)

您可以做的是添加自定义验证:

class User < ActiveRecord::Base
  belongs_to :role
  validate :existance_of_role

  private
    def existance_of_role
      if role_id && !Role.exists?(role_id)
        errors.add(:role, "must already exist.")
      end
    end
end

您还需要使用belongs_to :rolehas_one会将foreign_key置于Role模型的关系中而不是用户身上。

如果用户必须有角色。

此外,如果您想在数据库级别强制执行用户角色,您可以向users.role_id添加NOT NULL约束。

运行:rails g migration AddNotNullConstraintToUsers

然后编辑创建的迁移文件:

class AddNotNullConstraintToUsers < ActiveRecord::Migration
  def change
    change_column_null(:users, :role_id, false)
  end
end

运行迁移后,您可以更改验证,以便在role_id为nil时也会添加错误。

private
  def existance_of_role
    errors.add(:role, "must already exist.") unless Role.exists?(role_id)
  end

您可以对validates_presence_of :role执行相同的操作,但这不会强制该角色已预先存在。

答案 2 :(得分:1)

您可以在用户模型中添加此验证器

class User < ActiveRecord::Base
    has_one :role

    validate :role_id_exists

    def role_id_exists
      return false if Role.find_by_id(self.role_id).nil?
    end
end