← Building a bulletin board API with authentication authorization in Rails 6 # 16 policy settings
With the previous implementation, only the poster can edit or delete the post. However, I will extend it so that anyone can edit / delete posts when logged in as an administrator.
To do this, add an admin column to your user model.
$ rails g migration AddAdminToUsers admin:boolean
db/migrate/xxxxxxxxxxxxxx_add_admin_to_users.rb
# frozen_string_literal: true
class AddAdminToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :admin, :boolean, default: false, null: false
end
end
By the way, until now, I wrote the test after implementing the function, but I think that I understand the basic behavior of pundit, so I will write it from the test first.
Since the test that can not be edited and deleted when logged in as another user without administrator authority has already been written,
Let's implement. Strictly speaking, it is perfect to implement both policy test and request test, but here I will implement only policy.
If you like, don't look at the sample written here, but first try implementing it yourself and compare it, as it will be a practice to write code, so please try it.
spec/policies/post_policy_spec.rb
...
RSpec.describe PostPolicy, type: :policy do
let(:user) { create(:user) }
+ let(:admin_user) { create(:user, admin: true) }
let(:post) { create(:post) }
...
it "Not allowed when logged in but another user" do
expect(subject).not_to permit(user, post)
end
+ it "Allowed when logged in as admin user" do
+ expect(subject).to permit(admin_user, post)
+ end
...
spec/factories/posts.rb
...
remember_created_at { nil }
name { "MyString" }
tokens { nil }
+ admin { false }
end
...
After implementing so far, move rubocop and rspec and check. I haven't implemented the policy file yet, so the test is moss.
First, let's create a private method in application_policy.rb that determines that you are an administrator.
app/policies/application_policy.rb
...
private
def mine?
@record.user == @user
end
+
+ def admin?
+ @user.present? && @user.admin?
+ end
+
All that is left is to change the two judgments of update? Destroy? In post_policy.rb.
app/policies/post_policy.rb
def update?
- mine?
+ mine? || admin?
end
def destroy?
- mine?
+ mine? || admin?
end
That's it!
This is a bit thin article, so let's touch factoryBot to make it easier to create admin users.
spec/factories/users.rb
name { "MyString" }
tokens { nil }
admin { false }
+
+ trait :admin do
+ admin { true }
+ end
end
spec/policies/post_policy_spec.rb
RSpec.describe PostPolicy, type: :policy do
let(:user) { create(:user) }
- let(:admin_user) { create(:user, admin: true) }
+ let(:admin_user) { create(:user, :admin) }
let(:post) { create(:post) }
How about running rspec with this? If you can write without mistakes, you should pass the test.
As you can see, the trait can be used by passing it as an alias to the second argument such as create
in factoryBot.
If you just set the admin flag, there is little benefit and it doesn't make much sense, but if there is a column that you want to have an initial value as a set for admin users, for example, multiple columns will be added each time create
. You don't have to set the initial value.
Please use all means.
→ Building a bulletin board API with authentication authorization with Rails 6 # 18 ・ Implementation of final user controller [To the serial table of contents]