- Read Tutorial
- Watch Guide Video
In this video, we are going to create the functionality for the "approve" and "review" buttons on our admin homepage.
It's fairly straightforward for the "review" button, as it should just take the admin to edit page. So, simply change the path to edit_post_path
and pass pending approval
to it, just like this:
<!-- app/views/static/_pending_approval.html.erb --> <div class='col-md-6 column'> <%= link_to 'Review', edit_post_path(pending_approval), class: 'btn btn-warning btn-block' %> </div>
As for "approve", we want the admin to have the ability to approve a post just by clicking it. This is going to be a little bit more complex than "review". So, we'll have to create a test for it. Before that, let's create a new spec file in our features
folder, and call it homepage_spec.rb
.
In this file, we are going to begin by including the rails_helper
, and then create a describe
block called homepage. To test this, we need a post and an admin user, so we're creating both using FactoryGirl
. Next, we want the test case to visit the homepage and then, click on the "approve" button. We need an ID for this though, so we're going to add an id for the "approve" button in our _pending_approval.html.erb
file.
<!-- app/views/static/_pending_approval.html.erb --> <div class='col-md-6 column'> <%= link_to 'Approve', approve_post_path(pending_approval), class: 'btn btn-success btn-block', id: "approve_#{pending_approval.id}" %> </div>
So, now we want the test to expect the post to have a status of approved.
# spec/features/homepage_spec.rb require 'rails_helper' describe 'Homepage' do it 'allows the admin to approve posts from the homepage' do post = FactoryGirl.create(:post) admin_user = FactoryGirl.create(:admin_user) login_as(admin_user, :scope => :user) visit root_path click_on("approve_#{post.id}") expect(post.reload.status).to eq('approved') end end
As expected, the test fails, and that's what we want.
To fix, we have to do a few things. First, open the routes.rb
file and add a new route inside the resources
block.
# config/routes.rb resources :posts do member do get :approve end end
In this code, we are saying posts
should have a new route called "approve." Let's quickly check it in the console. Run rake routes | grep approve
, and you can see the new route.
Next, open the posts_controller.rb
file, and create a new method called approve
. Also, we need to add :approve
to the before_action
callback. In the approve
method, we simply have to set the status as "approved" and redirect the user to homepage. We should also have a notice that says the post has been approved.
# app/controllers/posts_controller.rb def approve @post.approved! redirect_to root_path, notice: "The post has been approved" end
Lastly, go to _pending_approval.html.erb
and change the path to approve_post_path
and send pending_approval
as its parameter.
<!-- app/views/static/_pending_approval.html.erb --> <div class='col-md-6 column'> <%= link_to 'Approve', approve_post_path(pending_approval), class: 'btn btn-success btn-block', id: "approve_#{pending_approval.id}" %> </div>
Let's run rspec
and see if everything works. And it's all fine.
Open the browser and click on the "approve" button. It works great!
Before we wrap up, I want to check if this can be hacked. Say an employee who is not an admin can find the post id, type it in the browser like this: "localhost:3000/posts/15/approve", and this would be approved. That's definitely something we need to fix it because we don't want any employee doing that.
To fix this, go to posts_controller.rb
, and call the authorize
method, like this:
# app/controllers/posts_controller.rb def approve authorize @post @post.approved! redirect_to root_path, notice: "The post has been approved" end
Also, we have to add the approve
method to our policy, and just call the admin
method from it. Since we already have a method that checks if the user is an admin user, it makes no sense to duplicate that code.
# app/policies/post_policy.rb def approve? admin? end
Now, if you try doing the same hacking action as before, you'll be redirected to the homepage and you'll get a notice saying that you're not authorized to perform this function.