ecs
ecs

Reputation: 718

Ruby on Rails: How to stop users changing url to view another user's page?

I've got it so that the show view on a customer's page links to all the orders that they have placed. When they click "Show", it takes them to the show view for that order. However, if they were to change the id of the order in the url, they can then see other people's orders. Please can someone help or suggest ways in which I can have it so that if someone was to try and view an order other than the one they have been directed to, they will be redirected to their customer page? I can get the redirect bit working fine, using:

redirect_to customers_path(session[:customer_id])

but how would I get the application to make sure that the customer can only view that order? I can't seem to use the sort of logic where I check that the order id equals the order id in the url, as that will always prove true!

Upvotes: 7

Views: 6918

Answers (7)

Asher
Asher

Reputation: 1

Basically you need to create Rails admin-- or admin to users and add validations to it bu setting up admin roles on those validations--

def set_admin

end 

before_action set-admin only :[:destroy, :update]

when adding admin set the boolean as false on default

Upvotes: 0

Mauro
Mauro

Reputation: 1271

(current_user.id == params[:id].to_i || is_writer?) || user_denied

In my case is_writer? check if the user can modify the order instead user_denied is a method with redirect and alert

Upvotes: 0

Phil_ish
Phil_ish

Reputation: 95

Slight mod on @BinaryMuse's solution using current_user helper from Devise, the "IF" conditional and different comparison operator (!=).

def show
@order = Order.find params[:id]
 if current_user.id != @order.user_id
    flash[:notice] = "MEAN MESSAGE HERE!"
    redirect_to orders_path(session[:current_user])
    return
  end
end

Upvotes: 1

waqas
waqas

Reputation: 1

You can also check the authorization plugin. Its better to design this so that you can use for other features as well. Do not rely on client side parameters for finding the identity of a user. More information here: http://www.rubyinside.com/authorization-permissions-plugin-for-rails-154.html

Upvotes: 0

Jacob Mattison
Jacob Mattison

Reputation: 51062

I recommend adding an authorization gem such as CanCan, which lets you set whether the user has access to do certain things (e.g. edit an order, view an order, etc.). This may come in handy in a lot of ways; you may want to have admin pages (for adding new products, say) that customers should never have access to.

Once you have that in place, you can restrict a customer's access so that they can only view or edit their own orders. In CanCan, you create a class called abilities.rb that looks something like:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.admin?
      can :manage, :all
    else
      can [:read, :update], Order, :user_id => user.id
    end
  end
end

That bit about can [:read, :update], Order, :user_id => user.id means "the (non-admin) user can read or update an Order if the order.user_id == user.id" (i.e. the current user's id).

Upvotes: 10

Michelle Tilley
Michelle Tilley

Reputation: 159125

Assuming than your Order model has some concept of "who owns this order," usually via an integer column called something like user_id, you can check to see if session[:customer_id] is equal to order.user_id (or whatever you call it).

You will generally keep this authorization code in your controllers.

class OrdersController
  ...

  def show
    @order = Order.find params[:id]
    unless session[:customer_id] == @order.user_id
      flash[:notice] = "You don't have access to that order!"
      redirect_to customers_path(session[:customer_id])
      return
    end
  end

  ...
end

As your application gets more complicated, you might look into authorization gems like CanCan to handle this logic.

Upvotes: 14

Max Scheiber
Max Scheiber

Reputation: 173

A good solution would be to delete the corresponding route and view in the first place. Instead, make some sort of page for a user to see his or her own orders.

I'm not sure which user authentication gem you're using, but if you're using Devise, you could write code like this:

<% current_user.orders.each do |order| %>
  <%= render order %>
<% end %>

If you wanted to keep your current view and route hierarchy, you could use this code on the user's page.

<% if current_user.eql?(@user) %>
  <%= # show order history %>
<% end %>

If not using Devise, I imagine that it can't be too difficult to write a current_user helper method to achieve the same functionality.

Upvotes: 1

Related Questions