Forum: Ruby on Rails null object pattern

6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-14 18:08
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.
80e4cb97cae5c8d745f72337d93fd8f2?d=identicon&s=25 MaD (Guest)
on 2009-03-14 18:36
(Received via mailing list)
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.
6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-14 21:30
MaD wrote:
> 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

Separate file in the model directory?

My objective is to avoid nil object errors when no user is logged in -
i.e. when session[:user] is nil.

However, I still need to call some instance methods on this object.

Please suggest me how can I do this?

>
> other than that you can load it whenever you want via include or
> require.
91a72b0ad3e43e3ef3a31816667ec694?d=identicon&s=25 bill walton (Guest)
on 2009-03-15 00:30
(Received via mailing list)
Hi Carlos,

On Sat, 2009-03-14 at 21:30 +0100, Carlos Santana wrote:

> My objective is to avoid nil object errors when no user is logged in -
> i.e. when session[:user] is nil.
>
> However, I still need to call some instance methods on this object.
>
> Please suggest me how can I do this?

I'm thinkin' I must be missin' somethin'.  Why can't you use...

do_somethin' unless session[:user].nil?

?

Best regards,
Bill
6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-15 00:50
In that case I won't get any user object.
Basically I am trying to implement in my application as mentioned here:
http://pivotallabs.com/users/nick/blog/articles/27...

For this I have some instance methods in User class. So the
'do_somethin' is basically not optional (only if user is logged in). So
as suggested in the article, I am trying to create a null object.

I also looked at acts_as_nullobject plugin: http://martincik.com/?p=22 .
But it is giving me some errors.

Any help/suggestions are welcome.


bill walton wrote:
> Hi Carlos,
>
> On Sat, 2009-03-14 at 21:30 +0100, Carlos Santana wrote:
>
>> My objective is to avoid nil object errors when no user is logged in -
>> i.e. when session[:user] is nil.
>>
>> However, I still need to call some instance methods on this object.
>>
>> Please suggest me how can I do this?
>
> I'm thinkin' I must be missin' somethin'.  Why can't you use...
>
> do_somethin' unless session[:user].nil?
>
> ?
>
> Best regards,
> Bill
81b61875e41eaa58887543635d556fca?d=identicon&s=25 Frederick Cheung (Guest)
on 2009-03-15 01:02
(Received via mailing list)
On Mar 14, 8:30 pm, Carlos Santana <rails-mailing-l...@andreas-s.net>
wrote:
> 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
6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-15 01:29
I put UnassignedUser class in a separate file and added
self.abstract_class = true and also included requirement of User class.
Still same error.

Any more guidelines?

CS.

Frederick Cheung wrote:
> On Mar 14, 8:30�pm, Carlos Santana <rails-mailing-l...@andreas-s.net>
> wrote:
>> 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
6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-15 04:53
It worked..
Had a typo.. :(

Thanks for the help.

Carlos Santana wrote:
> I put UnassignedUser class in a separate file and added
> self.abstract_class = true and also included requirement of User class.
> Still same error.
>
> Any more guidelines?
>
> CS.
>
> Frederick Cheung wrote:
>> On Mar 14, 8:30�pm, Carlos Santana <rails-mailing-l...@andreas-s.net>
>> wrote:
>>> 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
D3fc5887a2f39f2e0c8989d39ce5e6f9?d=identicon&s=25 Bharat Ruparel (bruparel)
on 2009-03-15 13:49
(Received via mailing list)
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
6c3acc025a63460a367b7981e606e032?d=identicon&s=25 Neubyr Neubyr (neubyr)
on 2009-03-15 16:43
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).

-
CS.


Bharat Ruparel 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
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.