Art Shayderov
Art Shayderov

Reputation: 5110

Is it safe to put reference to current user in User model in Rails?

You know, I think I have to check current user in the model callbacks (like before_update). Rather than rely solely on adding where ('something.user_id = ?', 'current_user.id') in the controllers. I need something like Thread.CurrentPrincipal in .NET
Is it safe to put reference to current user in User model? I'm sorry I don't really understand how it works under the hood yet.
Or how you do it The Rails way?
Sorry if this a silly question.

Added on 3/27
Oops
To get the right answer you have to ask the right question. And that's not an easy task in itself. How can it be that other people's questions are so obscure and they get their answers and your own question is so clear-cut but nobody understands it? :)
I do not understand where to put security check. That the user will get access only to his own stuff. On the controller level? And then test every action? "should not /view|create|edit|destroy/ other user's stuff"? I thought may be I can put it in the model and have one place to /write|refactor|test/. That's why I asked about how I can get a reference to the current user.
Actually I'm surprised I didn't find anything relevant in Rails Guides or Blogs. Some questions were asked but no authoritative "best practices" besides "don't do it".
After giving some thought I decided to just create in the controller before_filter the scope scoped to the current user and just rely on my own convention (promised to myself that I won't access the model directly). And just test it once per controller. That's not a banking application anyway.

Upvotes: 1

Views: 193

Answers (2)

Swanand
Swanand

Reputation: 12426

I don't really understand Thread.CurrentPrincipal, but current_user generally means the logged in user and that is completely a controller context. It is not available for use inside a model. So a hacky solution would be:

class UseCase < ActiveRecord::Base
  after_save :my_callback_method

  attr_accessor :current_user

  def my_callback_method
    # Some operations based on current_user
  end

  # ...
end

And then in your controller:

#...
use_case = UseCase.find(use_case_id) # Just an example, can be anything
use_case.current_user = current_user
# then this
use_case.save
# or basically
use_case.method_that_triggers_after_save_callback
#...

Warning: I am sure this is bad practise (I have never used it myself). But this will work. Ruby gurus / MVC gurus out there, please comment.

Upvotes: 0

Eimantas
Eimantas

Reputation: 49354

I'm not sure I get your situation. If you want to check if some other model's instance belongs to current user - use associations (I inferred that from "something.user_id = ?").

Else - in ActiveRecord before_update method is used on a per-instance basis. I.e. you pass current instance to that callback as an argument. Hence:

def before_update(current_user_instance)
  current_user_instance.do_something
end

Will yield any user instance as current_user_instance in the callback. So you can do following:

>> user_1 = User.find(1)
>> user_1.update_attribute(:some_attribute, 'some value')
>> user_2 = User.find(2)
>> user_2.update_attribute(:some_attribute, 'some other value')

This will call do_something method on separate instances (user_1 and user_2)

Upvotes: 1

Related Questions