9

I need to call current_user (define in ApplicationControler like an helper), in my User model.

I test ApplicationController.helpers.curret_user but not works:

irb(main):217:0> ApplicationController.helpers.current_user
NoMethodError: undefined method `current_user' for nil:NilClass

but this method works fine in controllers and views...

So how can I get my current user in model?

user229044
  • 232,980
  • 40
  • 330
  • 338
Matrix
  • 3,458
  • 6
  • 40
  • 76

3 Answers3

8

if you in your ApplicationController call helper_method :current_user

class ApplicationController < ActionController::Base
  helper_method :current_user

  def current_user
    @current_user ||= User.find_by(id: session[:user])
  end
end

Than you can call it in your helpers

more docs on

Simon1901
  • 341
  • 2
  • 8
7

You can't (or, at the very least, you really really shouldn't).

Your models have no access at all to your currently instantiated controller. Your models are supposed to be designed in such a way that there might not even be a request or a user actually interacting interactively with the system (think ActiveJob).

You need to pass current_user into your model layer.


Your specific problem is that you've invented something called helpers. That isn't a thing, it's nil, so you get your NoMethodError on nil:nilClass error. current_user is an instance method, so you would need to invoke it directly on an instance of your controller, not on the class itself.

user229044
  • 232,980
  • 40
  • 330
  • 338
  • ok, lot of things are forbidden, it's difficult to me. I'm accustomed to be free in choice AND rigorous in code... – Matrix Dec 28 '14 at 03:07
  • 3
    @Matrix You should give up on free choice. There are very strongly defined conventions in Rails, and you should follow them, especially at the beginning when you don't know enough to pick and choose which conventions can safely be disregarded. Rails as a whole is very powerful, but it does a *lot* for you, but only if you actually use it correctly. – user229044 Dec 28 '14 at 04:35
  • I agree you should follow the rails convention. You can see a sample of how I would recommend using it on a github project I have. https://github.com/camdixon/nku-rails/blob/master/app/controllers/application_controller.rb and then use it like this current_user and you can call attributes on it like current_user.id in views if needed. It's not a symbol so no need to use a colon in front or after it if you use it like I did in the github link. – camdixon Dec 28 '14 at 05:15
  • @camdixon Actually I wouldn't advise he use that controller as a basis. Your before filters aren't idiomatic by a stretch. Don't `return true`, that doesn't *do* anything. Either render/redirect, or do nothing. http://pastebin.com/3VRDm8im – user229044 Dec 28 '14 at 05:22
  • Ok, my bad for referencing it. Should I delete previous comment? Would you recommend using the current_user helper in that way? – camdixon Dec 28 '14 at 05:25
7

I just answered this here: https://stackoverflow.com/a/1568469/2449774

Copied for convenience:

I'm always amazed at "just don't do that" responses by people who know nothing of the questioner's underlying business need. Yes, generally this should be avoided. But there are circumstances where it's both appropriate and highly useful. I just had one myself.

Here was my solution:

def find_current_user
  (1..Kernel.caller.length).each do |n|
    RubyVM::DebugInspector.open do |i|
      current_user = eval "current_user rescue nil", i.frame_binding(n)
      return current_user unless current_user.nil?
    end
  end
  return nil
end

This walks the stack backwards looking for a frame that responds to current_user. If none is found it returns nil. It could be made more robust by confirming the expected return type, and possibly by confirming owner of the frame is a type of controller, but generally works just dandy.

Community
  • 1
  • 1
keredson
  • 3,019
  • 1
  • 17
  • 20