Read cookie

Jesús Gabriel y Galán wrote:

That should read Enumerable#find

If you understand what I'm trying to do, do you think the use of
Mechanize is a good or bad idea? Is it better to use the instance
variable to send the variable from controller to the model?

(As you said, probably more a Rails question. But now I'm here :slight_smile: )

···

--
Posted via http://www.ruby-forum.com/\.

Pål Bergström wrote:

The value displayed (which is the value in the cookie) is the timestamp
of the previous request.

But that's in the controller. Or do I miss something?

Yes, it's in the controller.

One more time:

1) I have a Rails app.

2) I have/had certain data aes encrypted in certain columns in mysql
with a unique key for each user. That key is saved in a cookie. If they
use an iPhone or another browser they need to ad the key to each
browser. It's just another layer of security on top of Rails. So if
someone get hold of that key it's useless unless you login or break the
security of mysql.

3) l use "before_save" and "fast-aes" in the model. So everything happes
in the model and in a script for encrypting located in /lib, just
because I can't get the cookie into the model with rails
cookies[:my_cookie]. Or can I? Maybe I'm overlooking something. Can get
the value of a cookie from the controller into the model in a simple
uniform way?

Ah right, so now you're definitely asking a Rails question. I think your
question is: how can I access request/controller parameters from an
instance of the model?

The brief answer is: you can't. An instance of a model exists
independently of any controller. A model can be instantiated outside of
a controller; and in principle, one model object could be shared between
multiple controller instances.

A simple solution is to pass the parameter explicitly. That is, in your
model you can have a method which accepts the encryption key as a
parameter, like 'decrypt' say, and invoke it from the controller:

  # code in controller
  ...
  thing = Thing.find(id)
  thing.decrypt(cookies["key"])
  ...

Or you could set an instance variable in the model (models can have
regular Ruby attrs, which are not stored in the database), which in turn
you can use in your before_save method.

If you want to make it completely transparent, there is a messy solution
you could consider, which is to use Thread-local variables. In your
controller's "before" filter, do

  Thread[:key] = cookies["key"]

Then this will be accessible in your model as Thread[:key]. You need to
be very careful to reset this variable before *every* controller action,
otherwise the key may leak from one user's request to another user.

This is actually how Rails deals with timezones - in the controller, if
you set Time.zone = xxx in the controller, it affects the model through
a thread-local variable. See

http://api.rubyonrails.org/classes/Time.html#method-c-zone%3D

and click on "show source".

I'd recommend you avoid doing this if you possibly can. I think in your
case, I'd use an instance variable.

class MyModel < ActiveRecord::Base
  attr_accessor :key

  def before_save
    raise "Key not set!" unless key
    ... encrypt using key
  end
end

class MyController < ApplicationController
  def create
    @thing = MyModel.new(params[:thing])
    @thing.key = cookies[:key]
    @thing.save!
  end
end

Of course, you do need to update your code at each point where you load
or save models, but there is no risk of one user's key hanging over to
another request.

This of course a 100% Rails question. If you didn't get a good answer on
a Rails forum, maybe you needed to be bit clearer in the phrasing of
your question. There is good advice at
http://www.catb.org/~esr/faqs/smart-questions.html#intro

In future I'd recommend you be more specific about what you're trying to
do; post samples of code; and mark the points where you're having
problems. One ambiguous sentence just doesn't cut it, and most people
are likely to skip over it.

HTH,

Brian.

···

--
Posted via http://www.ruby-forum.com/\.

Mechanize is a HTTP *client* - a programmable web browser if you like.

Rails is a HTTP *server*.

You wouldn't use Mechanize in a Rails app, unless your Rails app was in turn
connecting to a different web server and pulling information from that.

If you connected to your own web server using Mechanize, the web server
would see it as a new client, distinct from all your other clients, and
probably generate a new cookie for it.

···

On Tue, Sep 07, 2010 at 12:14:35AM +0900, Pål Bergström wrote:

If you understand what I'm trying to do, do you think the use of
Mechanize is a good or bad idea? Is it better to use the instance
variable to send the variable from controller to the model?

I answered what I did in case you were really looking after calling a
website and retrieving the cookie from the response. It seems that I
misunderstood your question, since it's obvious from the following
conversation that you were talking about retrieving the cookie from a
client's request. I don't know much about Rails, Brian and others have
given advice regarding that.

Now that your question is clear (reading a cookie from the request and
using it around controllers and models) you won't need Mechanize for
anything.

Jesus.

···

2010/9/6 Pål Bergström <pal@palbergstrom.com>:

Jesús Gabriel y Galán wrote:

That should read Enumerable#find

If you understand what I'm trying to do, do you think the use of
Mechanize is a good or bad idea? Is it better to use the instance
variable to send the variable from controller to the model?

(As you said, probably more a Rails question. But now I'm here :slight_smile: )

Brian Candler wrote:

  Thread[:key] = cookies["key"]

Sorry, that should have been

    Thread.current[:key] = cookies["key"]

···

--
Posted via http://www.ruby-forum.com/\.

Brian Candler wrote:

In future I'd recommend you be more specific about what you're trying to
do; post samples of code; and mark the points where you're having
problems. One ambiguous sentence just doesn't cut it, and most people
are likely to skip over it.

Thanks for your time and effort to answer. I appreciate it. I have given
detailed explanation for what I wanted to do several times (before
this). So I thought I would just ask: Can Ruby access a cookie in a
users browser? I could do it with cgi but not anymore.

I know I can pass it to the model with a params. But that means sending
it on many occasions instead of setting it once. Maybe you have given me
a solution to that with Thread-local variables. I will examine your
answer more closely.

I don't have the before_save and after_find in the controller. It's in
the model.

···

--
Posted via http://www.ruby-forum.com/\.

Pål Bergström wrote:

So I thought I would just ask: Can Ruby access a cookie in a
users browser?

And I say again, that question is completely meaningless. Ruby is a
programming language; it can do anything that a programming language can
do. But by itself it knows nothing about cookies - they are an artefact
of HTTP. So you need to be talking about a Ruby HTTP environment, such
as Rails or Sinatra or Rack or Webrick, which deals with incoming HTTP
requests. That's the "context" which someone else asked for.

All of these do have mechanisms for accessing cookies - even if it's
only directly accessing the HTTP Cookie: and Set-Cookie: headers - so
the answer to your question is quite clearly "Yes".

However, I imagine that "Yes" is not the answer you were looking for.

What you actually have is a problem, and you want help finding a
solution. In that case, you need to describe the specific problem.

"I cannot access cookies in Rails" is not sufficient - clearly you can,
and I showed you code which does it.

"in Rails, I cannot access cookies inside a model object" is getting
there. Or "I know how to access cookies inside the Rails controller but
not in other objects"

Even if you wrote some code in lib/foo.rb, this is still running in the
context some Ruby HTTP framework; how you access cookies depends on what
the framework provides. If it were running standalone it wouldn't
receive a HTTP request in the first place (unless you were writing a
HTTP server from scratch)

I could do it with cgi but not anymore.

That also means nothing unless you expand on "it" (what you're trying to
do), or the problem (you have some code which worked before but which
does not work now, in which case you can post the code itself and ask
for ways to rewrite it)

In the very old days, I think Rails had a global CGI object for "the
current request", since it was only ever intended to handle one request
at a time within any particular process. Now that Rails apps can be
multi-threaded, this will have been removed, as it wouldn't make any
sense - each controller instance must have its own HTTP request object.
They've also removed the use of the CGI library, since Rack does it
better and faster.

I don't have the before_save and after_find in the controller. It's in
the model.

Yes, it's part of the design of Rails that models have before_save and
after_find hooks. Note that ActiveRecord, from which you have built your
models, is also a part of Rails - albeit one which can be used outside
of Rails quite easily.

Regards,

Brian.

···

--
Posted via http://www.ruby-forum.com/\.

Brian Candler wrote:

you need to describe the specific problem.

I know. I believe I did that. As I said I've asked before, not this
time. But there is a reason for that. I think the problem is our
different mindsets. I don't know, so I ask stupid questions. You know
and don't really understand my problem and what I'm trying to do as my
question is unlogical.

Thank you for the clarification. I'll guess I will use the instance
variable and add it everywhere I need it. I was hoping I could avoid
that.

···

--
Posted via http://www.ruby-forum.com/\.

You could put it in a method in your ApplicationController, then in each of
your specific controllers, just use a before filter to apply it to the
methods you want. Then you only have to have one additional line in each of
the controllers that will use that before filter.

class ApplicationController < ActionController::Base
  def verify_key
    redirect_to some_path unless logged_in? &&
current_user.valid_key?(session['aes-key'])
  end
end

class ResourcesTypeOneController < ApplicationController
  before_filter :verify_key , :only => [:destroy, :edit , :update]
  # ...
end

class ResourcesTypeTwoController < ApplicationController
  before_filter :verify_key , :except => [:show]
  # ...
end

···

2010/9/4 Pål Bergström <pal@palbergstrom.com>

Thank you for the clarification. I'll guess I will use the instance
variable and add it everywhere I need it. I was hoping I could avoid
that.