Search code examples
ruby-on-railsrubyrolify

Error trying to create roles using rolify gem


How to use rolify gem? I've not been able to run it in the console to try it out. I followed the documentation. Getting this error from paper trail - ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR: null value in column "item_id" violates not-null constraint) DETAIL: Failing row contains (919, Role, null, create, null, null, 2022-11-25 11:24:25.649806, null, {"id": [null, 1], "name": [null, "admin"], "created_at": [null, ...).. I searched for it and found that some columns might be expecting UUID but getting an ID. My roles table looks like this -

# frozen_string_literal: true

class RolifyCreateRoles < ActiveRecord::Migration[6.1]
  def change
    create_table(:roles) do |t|
      t.string :name
      t.references :resource, type: :uuid, polymorphic: true

      t.timestamps
    end

    create_table(:users_roles, id: false) do |t|
      t.references :user, type: :uuid
      t.references :role
    end

    add_index(:roles, [:name, :resource_type, :resource_id])
    add_index(:users_roles, [:user_id, :role_id])
  end
end

I've spent a lot of time trying to debug it to no avail.

I can do User.first.roles and User.first.has_role?(:admin) but doing User.first.add_role(:admin) gives me the above error from the paper trail gem.

I also tried making the roles tables' ID as UUID but it throws me this error - ActiveRecord::StatementInvalid (PG::UndefinedFunction: ERROR: operator does not exist: uuid = bigint) LINE 1: ... "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_r... ^ HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.

My paper trail table looks like this -

def change
    create_table :versions do |t|
      t.string   :item_type, null: false
      t.uuid     :item_id,   null: false
      t.string   :event,     null: false
      t.string   :whodunnit
      t.text     :object, limit: TEXT_BYTES
      t.datetime :created_at
    end
    add_index :versions, %i[item_type item_id]
  end

I cannot change the item_id type to integer because we already have the whole application using it.

I am using rails 6.1 and ruby 2.7.


Solution

  • If you want to use a uuid instead of a bigint for the primary key you need to also set the type for any references to that table:

    class RolifyCreateRoles < ActiveRecord::Migration[6.1]
      def change
        create_table(:roles, id: :uuid) do |t|
          t.string :name
          t.references :resource, type: :uuid, polymorphic: true
          t.timestamps
        end
    
        create_table(:users_roles, id: false) do |t|
          t.references :user, type: :uuid
          t.references :role, type: :uuid # this was missing
        end
    
        add_index(:roles, [:name, :resource_type, :resource_id])
        add_index(:users_roles, [:user_id, :role_id])
      end
    end