B
Brian Candler
Pål Bergström said: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=
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.