Hiding Records from Non Authorized Users in Rails
In this guide we are going to continue building out our application's permission structure. Specifically we're going to work on ensuring that users are only able to see the posts that they created.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this guide we are going to continue building out our application's permission structure. Specifically we're going to work on ensuring that users are only able to see the posts that they created. This is a common permission structure requirement.

Our tests in post_spec.rb check to see if the posts index page can be reached successfully and if it is displaying a list of posts. However, we have to be more explicit on the types of posts it renders.

If you start the rails server and open the browser, you can see a list that includes all the posts - even those that were not created by a regular user.

large

Since this is sensitive payroll information, we don't want one user to see the overtime requested by employees. We have to ensure that the post we created is not visible to other users.

For that, open post_spec.rb, and let's add the following code to the index action specs:

# spec/features/post_spec.rb

it 'has a scope so that only post creators can see their posts' do
  post1 = Post.create(date: Date.today, rationale: "asdf", user_id: @user.id)
  post2 = Post.create(date: Date.today, rationale: "asdf", user_id: @user.id)

  other_user = User.create(first_name: 'Non', last_name: 'Authorized', email: "nonauth@example.com", password: "asdfasdf", password_confirmation: "asdfasdf")
  post_from_other_user = Post.create(date: Date.today, rationale: "This post shouldn't be seen", user_id: other_user.id)

  visit posts_path

  expect(page).to_not have_content(/This post shouldn't be seen/)
end

We have a specific flow for this test:

  1. It's creating multiple posts and associating them with the logged in user
  2. Then it creates another user and a new post that it associates with the other_user
  3. Next it visits the index page
  4. Lastly it expects the page to not display the posts associated with the other_user since that user is not the one accessing the page

If you run rspec it will fail, and that's what we want. Let's implement the code needed for getting this to work.

Go to posts_controller.rb, and implement this code:

# app/controllers/posts_controller.rb

def index
  @posts = current_user.posts
end

If you run rspec, it throws another error. However this is causing an error with a different test. This is a different error and it's caused by FactoryGirl not associating a post with the current user. When we start to polish the code we can clean this up and implement a custom method to fix this, but for now we're simply setting the user id of post to the current user id using an update call. You can update it as follows.

# spec/features/post_spec.rb

describe 'delete' do
  it 'can be deleted' do
    @post = FactoryGirl.create(:post)

    @post.update(user_id: @user.id)
    visit posts_path

    click_link("delete_post_#{@post.id}_from_index")
    expect(page.status_code).to eq(200)
  end
end

If you run the tests now they will all be passing.

Resources