2

Is there a way to use devise functions within a model? Let's say, a scope?

For reference, this is what I was thinking of:

scope :available, -> {
    if user_signed_in?
        requestable
    else
        requestable.where.not(books: {owner_id: current_user.id})
    end
}

I would need to use user_signed_in? and current_user in this scope. But I can't. Is there a way to do it?

Enrique Moreno Tent
  • 24,127
  • 34
  • 104
  • 189
  • Why can't you use them? Both of those methods are available in other models, for example a `User` model would require devise, as that is the purpose of the gem. – jkeuhlen Aug 06 '15 at 14:21
  • Ohh duh. They are set up to be used within controllers not models. I was being forgetful sorry! – jkeuhlen Aug 06 '15 at 14:23
  • So the answer would be a straight 'No'? That would be ok (just disappointing) :( – Enrique Moreno Tent Aug 06 '15 at 14:23
  • It is highly discouraged.... I'll write up a quick answer but I'm not sure how much help I can be. – jkeuhlen Aug 06 '15 at 14:24
  • Seems like I was beat to it! After looking at axel's answer, I'd actually mark this as a duplicate of the question he linked (even though it is not strictly devise, it is essentially the same problem/solution) http://stackoverflow.com/questions/1568218/access-to-current-user-from-within-a-model-in-ruby-on-rails – jkeuhlen Aug 06 '15 at 14:28
  • Maybe not a duplicate, but fairly similar. I guess the answer is `It can#t be done, and it shouldn't`. I will be accepting his, since it adds quite some reasoning to it. thanks to everyone who contributed. – Enrique Moreno Tent Aug 06 '15 at 14:29
  • Unfortunately it is not a very helpful answer, but is the only one I know of. Good luck! – jkeuhlen Aug 06 '15 at 14:31

2 Answers2

2

current_user (and same goes for devise helpers such as user_signed_in?) is only available in your controllers. I've been around that question and ended up by passing current_user to my scopes and model's methods.

In the model:

scope :available, -> (current_user, signed_in) {
    if signed_in
        requestable
    else
        requestable.where.not(books: {owner_id: current_user.id})
    end
}

In the controller:

MyModel.available(current_user, user_signed_in?)

An alternative would be to use request_store (rack based global data storage) to store the current_user of the current request

Benjamin Bouchet
  • 12,971
  • 2
  • 41
  • 73
  • 1
    I guess I am better off doing the logic about the user in the controller, and adapt my scopes around it. Passing in them as parameters feel clunky. Thanks for the answer. – Enrique Moreno Tent Aug 06 '15 at 14:27
  • 1
    Good thought. Though I feel that's perhaps where MVC reach its limits, cause it seems right to me to have data such as `current_user` to be globally accessible – Benjamin Bouchet Aug 06 '15 at 18:05
1

Methods like these are not meant to be used in models. Models are supposed to work outside the controller as well (i.e. directly from the Rails console).

For a more detailed reasoning see:

Access to current_user from within a model in Ruby on Rails

Further there is no global 'store' knowing which users are currently signed in - this is determined within a request, by veryfying the user sends valid session information with his request.

Community
  • 1
  • 1
Axel Tetzlaff
  • 1,355
  • 8
  • 11