Protecting records from public view

OK, sorry mental block, I do this sort of thing at the moment


redirect_to :action => ‘show_invoice’, :id => @enquiry

def show_invoice
@enquiry = Enquiry.find(params[:id])
end


This works fine as far as it goes, it finds the invoice and dsiplays it
(my show_invoice view obviously handles the display). The URL looks
something like this.

http://foo/bar/show_invoice/18

That’s fine but the user can change 18 to say 17 and see the previous
invoice!

What’s the elegant (hopefully simple) solution?

bb.

I think you should look into filters and set a filter before on the
action to check if that user has been granted access to that invoice
(it belongs to him) or not.
Just google “rails before filter” and you’ll find plenty of examples.

On Sep 5, 12:06 pm, bingo bob [email protected]

On Sep 5, 12:06 pm, bingo bob [email protected]
wrote:


This works fine as far as it goes, it finds the invoice and dsiplays it
(my show_invoice view obviously handles the display). The URL looks
something like this.

http://foo/bar/show_invoice/18

That’s fine but the user can change 18 to say 17 and see the previous
invoice!

Typically you only care about stopping users seeing other users’
invoices. Assuming current_user returns the currently logged in user
and user has_many :invoices then

current_user.invoices.find params[:id]

is a normal find (so you could pass any of the things you could
normally pass to Invoice.find) but is scoped to only those invoices
belonging to that customer

Fred

On 5 Sep 2008, at 11:26, bingo bob wrote:

belonging to that customer

Fred

Hmm, bit confused, the form is available without any login, it’s
publically available.

ok, i assumed it wasn’t.

I suppose I’d like to scope the find in this method so that it only
returns the enquiry jsut submitted. It’s easy surely, oh maybe I don’t
need a find method at all?

Two separate users create a new invoice. How do you know to let user A
access their invoice but not other ones, and user B access only their
invoice ? How do you differentiate the two cases?

Fred

Two separate users create a new invoice. How do you know to let user A
access their invoice but not other ones, and user B access only their
invoice ? How do you differentiate the two cases?

I’m thinking that the app knows about the invoice just created (by ID).
Can I store this and limit the view to display just that ID (and no
other).

Typically you only care about stopping users seeing other users’
invoices. Assuming current_user returns the currently logged in user
and user has_many :invoices then

current_user.invoices.find params[:id]

is a normal find (so you could pass any of the things you could
normally pass to Invoice.find) but is scoped to only those invoices
belonging to that customer

Fred

Hmm, bit confused, the form is available without any login, it’s
publically available.

I suppose I’d like to scope the find in this method so that it only
returns the enquiry jsut submitted. It’s easy surely, oh maybe I don’t
need a find method at all?

Just need the one record previously saved.

On 5 Sep 2008, at 11:51, bingo bob wrote:

Can I store this and limit the view to display just that ID (and no
other).

After creation you could just render the newly created invoice and do
away with the show action entirely.

Two disadvantages with this (over the traditional redirect)

  • if the user reloads the page it will resubmit the form which created
    the invoice
  • no way for people to get at the invoice again once they’ve navigated
    away from that page.

Another approach would be to keep almost everything the same, but
store the id of the freshly created invoice in the session and only
read it from the session, not the params (this will also stop the user
from viewing their invoice again once they’ve relaunched their browser).

Yet another option is to store a persistent cookie with the user’s id
and track the user using that (to implement the scoped find I
mentioned earlier)

Fred

On 5 Sep 2008, at 12:32, bingo bob wrote:

Many thanks for this, sounds like just the ticket, would you mind
providing a brief code example for the syntax (am sure I can fill in
the
gaps)?

well instead if doing find params[:id] you do find
session[:something], having previously set session[:something]
appropriately

Fred

Another approach would be to keep almost everything the same, but
store the id of the freshly created invoice in the session and only
read it from the session, not the params (this will also stop the user
from viewing their invoice again once they’ve relaunched their browser).

Many thanks for this, sounds like just the ticket, would you mind
providing a brief code example for the syntax (am sure I can fill in the
gaps)?

well instead if doing find params[:id] you do find
session[:something], having previously set session[:something]
appropriately

Sorry Fred, Not sure I follow, can I set x = session[:enquiry_id]
(in the create) then do, find x basically in the show ?

On 5 Sep 2008, at 14:27, bingo bob wrote:

well instead if doing find params[:id] you do find
session[:something], having previously set session[:something]
appropriately

Sorry Fred, Not sure I follow, can I set x = session[:enquiry_id]
(in the create) then do, find x basically in the show ?

No. after you’ve created the enquiry
session[:enquiry_id] = …

in the show

@enquiry = Enquiry.find session[:enquiry_id]

Fred

No. after you’ve created the enquiry
session[:enquiry_id] = …

in the show

@enquiry = Enquiry.find session[:enquiry_id]

Fred

Tried that, fine still working but still the user can edit the URL and
get to other records?

On 5 Sep 2008, at 16:16, bingo bob wrote:

Tried that, fine still working but still the user can edit the URL and
get to other records?

not if you’re doing it right, because you’re not using the params from
the url.

Fred