null object pattern

I am trying to create a null object in my application. I would like to assigned a null user object for anonymous/ mot-logged-in user, i.e. if session variable has nil data.

In my User model, I have created a subclass like this: class UnassignedUser < User

  def save     false   end

  def update     false   end

  def username     "Unassigned"   end

  def county_id     "-999"   end

  def role_id     "5"   end end

When I go to console to try out this model following is the output:

UnassignedUser.new

NameError: uninitialized constant UnassignedUser         from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:278:in `load_missing_constant'         from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:467:in `const_missing'         from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:479:in `const_missing'         from (irb):1

User.new

=> #<User id: nil, username: nil, section_id: nil, password_hash: nil, password_salt: nil, role_id: nil, member_number: nil, tm_zone_info: nil, region_id: nil>

UnassignedUser.new

=> #<UnassignedUser id: nil, username: nil, section_id: nil, password_hash: nil, password_salt: nil, role_id: nil, member_number: nil, tm_zone_info: nil, region_id: nil>

If I create user object first and then unassigneduser then it does not give any error (although it is not doing what I intend to do).

Can anyone please elaborate on how to use null object pattern?

Thanks, CS.

If you have a construct like this (all in the same file):

  # app/models/user.rb   class User < ActiveRecord::Base     # ...   end

  class UnassignedUser < User     def self.shout       puts "yeah"     end   end

script/console will behave like this:   >> UnassignedUser.shout   NameError: uninitialized constant UnassignedUser (...)   >> User   => User(id: integer, login: string, email: string, password: string, created_at: datetime, updated_at: datetime)   >> UnassignedUser.shout   yeah   => nil

UnassignedUser gets only loaded when User is loaded. put it in its own file and maybe add:   self.abstract_class = true

other than that you can load it whenever you want via include or require.

Hi Carlos,

MaD wrote: > UnassignedUser gets only loaded when User is loaded. put it in its own > file and maybe add: > self.abstract_class = true

Separate file in the model directory?

Yes. The think to understand is that if your app hits the constant Foo, rails will try and load foo.rb hoping that it defines Foo. If there is no such foo.rb because Foo is in fact declared in bar.rb then this don't work. You need to either put things where rails will find them automatically or explicitly require them (using require_dependency)

Fred

It worked.. Had a typo.. :frowning:

Thanks for the help.

Carlos Santana wrote:

Hello Carlos, I am glad it worked for you. Access control is a fundamental requirement along with authentication. Jim Neath's Bort which is available on Github, packages Role Requirements written by Tim Harper along with Restful Authentication for creating a baseline application. Tim has done an excellent job of implementing a "minimal" authorization plugin. I am using Bort to develop my own toolkit for creating applications. I looked at the article that you list above. It is very well written and very nice to learn from. The key thing missing from it is that it fails to deal with Roles and instead deals directly with users. I think a minimal layer of roles between users and controllers is a key requirement. I am not saying that Role Requirement is the only plugin that addresses it. It is just that it packaged with Bort which has other key plugins in addition to Restful Authentication and Role Requirements. Gets the job done. So instead of saying session[:current_user].nil? you may want to say [:current_user].has_role?('anonymous') for example. See the method "has_role?" provided by Role Requirement? That is the key in my opinion. I may be wrong, but that is where I am going with this. Hope this helps. Bharat

I have a roles table and I check authorization as:

  def can_be_deleted_by?(user)       return false if user.role.nil?       valid_roles = %w{admin creator}       return false unless user.username == self.creuser || valid_roles.include?(user.role.name)       return true   end

One other thing I had to modify after using null obect was to check user.role.nil? before calling user.role.name, which otherwise checks for nil.name for anonymous user.

The delete action can be performed only by admin or the one who created that topic/item. Hence I am using roles as well as check by username(creator).