Accessing current_user from within a model: just don't do it
I came across a situation where I thought I wanted to access the current_user
from within a model, but it was just a case of mistaken thinking. Making session variables like current_user
accessible to a model is a break with convention, and breaking with conventions is usually a bad idea. So, the rule is: don’t do it unless you have exhausted all other options. There is a probably an easier way of doing what you are trying to do.
Here was my situation. I had users logging in to an application and signing up for various groups. The relationship between models was as follows:
class Users < ActiveRecord::Base has_many :memberships, :dependent => :destroy has_many :groups, :through => :memberships end class Groups < ActiveRecord::Base has_many :memberships, :dependent => :destroy has_many :users, :through => :memberships end class Memeberships < ActiveRecord::Base belongs_to :user belongs_to :group end
When a user created a new group, I wanted them to be added automatically to the group through a membership table, so at first I did something like this:
@group = Group.create(params[:group])
But, in doing this, I had already made an elementary mistake. Assuming the current_user
is accessible to the controller, something like this would obviously have been better:
@group = current_user.groups.create(params[:group])
In other words, if I had written current_user.groups.create
instead of just Group.create
, the Membership table would have been updated automatically.
As an alternative, say I wanted to set up the current_user
as the owner of the group, I could possibly do this:
@group = current_user.own_groups.create(params[:group])
Instead of adding the current_user
as a member of the new group, I could make the current_user
the owner (i.e. it’s the current_user’s ‘own group’). This would also need the following new line in the User model:
has_many :own_groups, :through => :memberships, :class_name => 'Group', :foreign_key => 'group_id'
And in the Group model:
has_one :owner, :through => :memberships, :class_name => 'User', :foreign_key => "id"
However, there is another—and my preferred—way of doing this. Rather than have the relationship defined in the Group model as a foreign key, the ‘ownership’ of the group can be defined in the Membership model, as a kind of membership.
This keeps the responsibility where it probably belongs, in the relationship (i.e. Membership) model. It also makes it easier to change the definition of ‘ownership’ at a future date, so that a group could have more than one ‘owner’. In other words, it’s a more flexible design.