NetManiac

Witold Rugowski on web20 wave with Ruby on Rails

Passing current user id to Rails models

Posted on November 30, 2011 - Filed Under RubyOnRails

If you're new here, you may want to subscribe to my RSS feed. You can also get updates by email Thanks for visiting!

Long time since last post, isn’t it? Well, I’m completely busy with my work in Nettigo, selling Arduinos and other nice gears :) I do not do gigs anymore, so there is a lot less reasons to write about Rails.

But I still use this framework, since my backend software is written in Rails, so here is one thing which I think can be useful for You.

Often we want to pass ID of current user to Rails model internals. Most answers are don’t do that, this is controller work to do authorization stuff, MVC is to prevent such thins, etc.

here was not related picture (as usual on this blog). Some readers were complaining it was not only unrelated but even offending. Well, maybe they were right, so, I have removed that picture.

Yeah, right, but what if we want to keep some kind of audit trail what is happening with given model? This is not authorization, just who done what.

Since in my application case audit records are created in observers simple passing user id as some additional parameter is no go for me – I don’t want to change interface just to pass user info, that breaks too much things.

So, I have chosen this approach:

def with_user user, &block
  if user.blank?
    yield
  else
    Thread.current[:user] = user.id
    yield
    Thread.current[:user] = nil
  end
end

And each operation I want to track I invoke:

with_user(current_user) do
 model.do_some_stuff
end

Thread.current acts as a hash accessible in current thread and allow us to pass some info skipping MVC isolation (You wanted that, right? :) )

In observers I can access user ID and store it with record. If it is not present, audit trails is being marked as created by System. That means probably cron job, or console action (well on console I can run code inside with_user block when needed).

This is safe as long each request is being processed in single thread and we make sure that user ID will be cleared after our operation. When ID will stay in Thread.current, next request being processed by this Rails app instance will have access to that value and wrong audit records will be created.

Code has to be updated, since any exception will occur inside block, code after yield will be skipped and user ID won’t be erased from Thread.current. Here it is, final version:

def with_user user, &block
  if user.blank?
    yield
  else
    Thread.current[:user] = user.id

    begin
      yield
    ensure
      Thread.current[:user] = nil
    end
  end
end

Code inside ensure will be executed each time – both when exception was raised and when execution was clean.

Popularity: 43% [?]

Hits for this post: 53756

Similar Posts

Comments

6 Responses to “Passing current user id to Rails models”

  1. reddit for ruby hackers on November 30th, 2011 13:34

    Kramer auto Pingback[...] you like or dislike and help decide what's popular, or submit your own! 1•••Passing current user id to Rails models (nhw.pl)submitted 2 [...]

  2. Craig Webster on November 30th, 2011 18:02

    How about this instead, which doesn’t violate MVC?

    class AuditedAction
      attr_accessor :user
      private :user=, :user
    
      def initialize user
        self.user = user
      end
    
      def execute message
        AuditLogEntry.create! :user => user, :message => message
        yield
      end
    end
    

    In a controller:

    def create
      AuditedAction.new(current_user).execute "create a thingy" do
        Thingy.create! ...
      end
    end
    

    Bonus points: when I try to create a Thingy somewhere that it’s not probably that I’ll have a current_user (eg in the console or in a script) I don’t have my

  3. Tweets that mention Passing current user id to Rails models : Witold Rugowski aka NetManiac -- Topsy.com on November 30th, 2011 19:15

    Kramer auto Pingback[...] This post was mentioned on Twitter by Ruby News, Pete Birkinshaw, Tom Stuart, Joel AZEMAR, Delicious Ruby Rails and others. Delicious Ruby Rails said: Passing current user id to Rails models : Witold Rugowski aka NetManiac: http://t.co/W6ErNkiN [...]

  4. arnodmental on November 30th, 2011 19:21

    Hi,
    Sorry if this sounds stupid but how do you then, access the user from your model ? is it using again Thread.current ?

    def do_something_in_my_model
      do_something_with_user Thread.current[:user]
    end
    
  5. The Ruby Reflector on November 30th, 2011 21:13

    Kramer auto Pingback[...] Passing current user id to Rails models By Witold Rugowski of NetManiac 21 hours ago. [...]

  6. mebcia on December 1st, 2011 12:32

    Awesome you removed the picture, thanks. :)

Leave a Reply