views:

279

answers:

5

I have 3 tables

items (columns are:  name , type)
history(columns are: date, username, item_id)
user(username, password)

When a user say "ABC" logs in and creates a new item, a history record gets created with the following after_create filter. How to assign this username ‘ABC’ to the username field in history table through this filter.

class Item < ActiveRecord::Base
  has_many :histories
  after_create :update_history
  def update_history
    histories.create(:date=>Time.now, username=> ?) 
  end
end

My login method in session_controller

def login
  if request.post?
    user=User.authenticate(params[:username])
    if user
      session[:user_id] =user.id
      redirect_to( :action=>'home')
      flash[:message] = "Successfully logged in "
    else
      flash[:notice] = "Incorrect user/password combination"
      redirect_to(:action=>"login")
    end
  end
end

I am not using any authentication plugin. I would appreciate if someone could tell me how to achieve this without using plugin(like userstamp etc.) if possible.

A: 

You may create a helper_method in application_controller.rb for global access to your "current user". You may refer to Ryan's great railscasts for details: http://asciicasts.com/episodes/160-authlogic (which is about interfacing with authlogic plugin).

ohho
+4  A: 

It is not a common practice to access the current_user within a model. That being said, here is a solution:

Add a class level attribute to the User model.

class User < ActiveRecord::Base
  def self.current_user
    Thread.local[:current_user]
  end

  def self.current_user=(usr)
    Thread.local[:current_user] = usr
  end
end

Set the current_user attribute in a before_filter of ApplicationController.

class ApplicationController < ActionController::Base
  before_filter :set_current_user
  def set_current_user   
    User.current_user = User.find(session[:user_id]) rescue nil
  end
end

Set the current_user after successful authentication:

def login
  if request.post?        
    if User.current_user=User.authenticate(params[:username], params[:password])
      session[:user_id] =User.current_user.id
      flash[:message] = "Successfully logged in "
      redirect_to( :action=>'home')
    else
      flash[:notice] = "Incorrect user/password combination"
      redirect_to(:action=>"login")
    end
  end
end

Finally, refer to current_user in update_history of Item.

class Item < ActiveRecord::Base
  has_many :histories
  after_create :update_history
  def update_history
    histories.create(:date=>Time.now, :username=> User.current_user.username) 
  end
end
KandadaBoggu
hey this is an excellent solution! i've favourited the question because of this
stephenmurdoch
Note that this solution is not threadsafe, so be careful with JRuby deployments etc.
molf
A: 

Simply way: replace

user=User.authenticate(params[:username])

to

@current_user =User.authenticate(params[:username])  
potapuff
+1  A: 

Why are you doing it this way? if the user creates an item, shouldn't the item have a belongs_to :user clause? and this would allow you in your after_update to do

History.create :username => self.user.username

Faisal
A: 

Hi KandadaBoggu,

I tried this solution but it does not let me login at all(not even with admin as username). Can you help me out with this or suggest some other way of doing this? The item model is not associated with the user model in any way. Though history has user_id History.create :username => self.user.username does not work.

Thanks

LearnRails
You have to make sure the `authenticate` method returns a `User` object upon successful authentication. Check if your `authenticate` works in the `irb` console. I also noticed that you are not passing password to the `authenticate` method in your sample code. I am assuming you are using password for authentication in your live system.
KandadaBoggu