Forum: Ruby on Rails fetch method of session hash

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Doug J. (Guest)
on 2009-05-03 06:51
(Received via mailing list)
Is there something special about the session hash that would make it
so that I can not access its associated fetch method?  In attempting
to do so I keep getting complaints that there is no such method.
Thanks for any input.

             ... doug
7stud -. (Guest)
on 2009-05-03 07:30
Doug J. wrote:
> Is there something special about the session hash that would make it
> so that I can not access its associated fetch method?  In attempting
> to do so I keep getting complaints that there is no such method.
> Thanks for any input.
>
>              ... doug

It's not a hash; it only appears to be hash like?  For instance,

class H
  def initialize
    @container = {}
  end

  def [](key)
    @container[key]
  end

  def []=(key, val)
    @container[key] = val
  end
end

h = H.new
h["red"] = 10

puts h["red"]
puts h.fetch

--output:--
10
r1test.rb:19: undefined method `fetch' for #<H:0x24f2c
@container={"red"=>10}> (NoMethodError)
Doug J. (Guest)
on 2009-05-03 09:07
(Received via mailing list)
> It's not a hash;

Well, that probably goes a long way towards explaining the absence of
the fetch method. :)  Thanks a lot for the detailed explanation.

     ... doug
Julian L. (Guest)
on 2009-05-03 14:13
(Received via mailing list)
It responds to fetch just fine for me. Can you send the code and error?

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/
7stud -. (Guest)
on 2009-05-03 16:09
Julian L. wrote:
> It responds to fetch just fine for me. Can you send the code and error?
>

Hey, me too!

class StoreController < ApplicationController

  def index
    session[:test] = 10

    puts "***************"
    print "[]: ", session[:test]
    puts
    print "fetch: ", session.fetch(:test, "Couldn't find.")
    puts
    print "fetch: ", session.fetch(:bird, "Couldn't find bird.")
    puts
    puts "****************"
  end

end


--output in server window:--
***************
[]: 10
fetch: 10
fetch: Couldn't find bird.
****************
7stud -. (Guest)
on 2009-05-03 16:26
7stud -- wrote:
> Julian L. wrote:
>> It responds to fetch just fine for me. Can you send the code and error?
>>
>
> Hey, me too!
>

Also,

class StoreController < ApplicationController

  def index
    session[:test] = 10

    puts "**********"
    c = session.class
    puts c
    puts c.superclass
    puts "**********"
  end

end


--output in server window:--
**********
ActionController::Session::AbstractStore::SessionHash
Hash
**********
Doug J. (Guest)
on 2009-05-03 20:12
(Received via mailing list)
> Can you send the code and error?

Sure.  Here's the offending line:

session[:target_uri]='/admin' if !session.fetch(:target_uri,nil)

And here's the full controller code (See specifically line 10)

      1 class LoginController < ApplicationController
      2
      3   def login()
      4 #   begin
      5       if defined? params && params.has_key?('login')
      6         record=Admin.find(:first,:conditions=>["Login=?",params
['login']])
      7         if record && record.Password==params.fetch
('password','')
      8           session[:user_id]=record.id
      9           session[:login]=record.Login
     10           session[:target_uri]='/admin' if !session.fetch
(:target_uri,nil)
     11           uri=session[:target_uri]
     12           session[:target_uri]=nil
     13           redirect_to(uri) && return
     14         else
     15           session=nil
     16           redirect_to(:action=>'index') && return
     17         end
     18       end
     19 #   rescue
     20 #     redirect_error($!)
     21 #   end
     22   end

And finally, here's the error message:

NoMethodError in LoginController#login
undefined method `fetch' for #<CGI::Session:0xb6c036ac>

Thanks.

       ... doug
Frederick C. (Guest)
on 2009-05-03 21:12
(Received via mailing list)
On May 3, 5:11 pm, djolley <removed_email_address@domain.invalid> wrote:

> And finally, here's the error message:
>
> NoMethodError in LoginController#login
> undefined method `fetch' for #<CGI::Session:0xb6c036ac>

You're running a different rails version (2.2.2 or less), whereas the
others must be using 2.3.2 (session handling got a revamp).

Fred
Doug J. (Guest)
on 2009-05-03 22:25
(Received via mailing list)
> You're running a different rails version (2.2.2 or less), whereas the
> others must be using 2.3.2 (session handling got a revamp).

Two things:

1.  Under the revamp is 'session' a real hash?

2.  From my code you probably saw what I was trying to do.
Specifically, I was attempting to use the fetch method to test whether
a specific key was in the session hash and return nil if it wasn't.
I'm wondering what the best way to do this is knowing what's coming
down the pike.  Maybe (and it scares me to even think about this) I
could somehow add a fetch method to the quasi session hash.  Then my
code would be compatible with what's coming in the later version.  I'm
pretty darn sure that I'm not smart enough to do that; but, it's
something to think about.  Any suggestions on how I should handle
this?  Thanks.

         ... doug
Frederick C. (Guest)
on 2009-05-03 23:42
(Received via mailing list)
On May 3, 7:24 pm, djolley <removed_email_address@domain.invalid> wrote:
> > You're running a different rails version (2.2.2 or less), whereas the
> > others must be using 2.3.2 (session handling got a revamp).
>
> Two things:
>
> 1.  Under the revamp is 'session' a real hash?
>
it's a special hash (because there's crafty stuff to do with lazy
loading)

> 2.  From my code you probably saw what I was trying to do.
> Specifically, I was attempting to use the fetch method to test whether
> a specific key was in the session hash and return nil if it wasn't.
> I'm wondering what the best way to do this is knowing what's coming
> down the pike.  Maybe (and it scares me to even think about this) I
> could somehow add a fetch method to the quasi session hash.  Then my
> code would be compatible with what's coming in the later version.  I'm
> pretty darn sure that I'm not smart enough to do that; but, it's
> something to think about.  Any suggestions on how I should handle
> this?  Thanks.

Is
if session[:foo]
 ...

not good enough for you (or do you sometimes explicitly store nil in
the session (and want that to be distinct from the value not being
there at all) ?) ?

Fred
Doug J. (Guest)
on 2009-05-04 00:15
(Received via mailing list)
> Is
> if session[:foo]
>  ...
>
> not good enough for you (or do you sometimes explicitly store nil in
> the session (and want that to be distinct from the value not being
> there at all) ?) ?

Actually the distinction between nil and nothing is exactly the issue;
but, it's not what you're thinking.  It has to do with the definition
of truth.

My understanding is that in Ruby what is not true is limited to either
nil or the constant, false.  My recollection is that, in the past on
some occasions, I have gotten myself into trouble by treating the
absence of a value as being equivalent to false. So, I keep reminding
myself that, in Ruby, the absence of a value is not equivalent to
false and I try to write code accordingly.

Now, I want to clarify the above statement.  My recollection of the
cases in which I have previously gotten into trouble didn't involve a
hash; but, rather, I was doing something like, "if foo" and the
trouble arose when the foo variable had not been defined. So, I
realize that is not the same thing as a key being absent from a hash.
Perhaps I can get away with it in the case of a hash.  If so, I'm just
going to have to expand my understanding of what constitutes false in
Ruby to include the absence of a key from a hash.  So, out of
curiosity, is it your understanding that, in Ruby, false includes the
absence of a key from a hash?

Thanks.

     ... doug
Frederick C. (Guest)
on 2009-05-04 00:41
(Received via mailing list)
On May 3, 9:14 pm, djolley <removed_email_address@domain.invalid> wrote:
> absence of a key from a hash?
it's not so much what constitutes false as what [:foo] returns if the
hash doesn't have a value for that key (and by default that's nil)

Fred
7stud -. (Guest)
on 2009-05-04 01:08
Doug J. wrote:
> If so, I'm just
> going to have to expand my understanding of what constitutes false in
> Ruby to include the absence of a key from a hash.
>

Your understanding of what 'evaluates' to false in a boolean setting,
like an if statement, is spot on.  false obviously evaluates to false,
but the only other thing that evaluates to false is nil.

The thing you need to expand your understanding of is: the possible
return values of the methods you call.  A hash returns nil if the key
doesn't exist (or a default value if a default value was set when the
hash was created).

So, yeah you can rely on a hash returning nil if the key doesn't exist,
and also that nil will evaluate to false.

> So, out of
> curiosity, is it your understanding that, in Ruby, false includes the
> absence of a key from a hash?
>

I don't think of it in such abstract terms.  If I the key doesn't exist,
the '[]' method returns nil.

> Actually the distinction between nil and nothing

Actually, it's the distinction between nil and false and anything else.
If the object you are evaluating in an if statement is not specifically
nil or false, then it will evaluate to true, period.  A concept like
"absence of nothing" is totally irrelevant and not worth thinking about.
Experienced programmers in other languages often get tripped up by ruby
because they expect things like empty strings(""), empty arrays([]) or
empty hashes({}) to evaluate to false.  But because none of those things
is specifically false or nil, they evaluate to true.  It's that simple.
7stud -. (Guest)
on 2009-05-04 01:21
7stud -- wrote:
>
> Experienced programmers in other languages often get tripped up by ruby
> because they expect things like empty strings(""), empty arrays([]) or
> empty hashes({}) to evaluate to false.  But because none of those things
> is specifically false or nil, they evaluate to true.  It's that simple.
>

Oh, yeah.  I forgot about the big one: 0 (zero).  In languages like C
and C++, 0 evaluates to false.  But in ruby 0 is not the value false or
nil, so 0 evaluates to true.  That one trips up a lot of programmers.

So when your method returns a value and you want to know if that value
will be considered true or false in an if statement, here is your check
list:


1) Is the value actually the value false?
2) Is the value nil?

If you answered 'yes' to 1 or 2, then value will evaluate to false in an
if statement.

3) Is the value something other than false or nil?

If yes, then the value will evaluate to true in an if statement.
7stud -. (Guest)
on 2009-05-04 01:40
7stud -- wrote:
>
>> So, out of
>> curiosity, is it your understanding that, in Ruby, false includes the
>> absence of a key from a hash?
>>
>
> I don't think of it in such abstract terms.  If I the key doesn't exist,
> the '[]' method returns nil.
>

By the way, using fetch like this:

fetch (akey, nil)

returns the exact some thing as the method '[]' (as long as no default
value was specified for a hash when it was created):

h = { "red" => 2, "blue" => 15}

puts h["green"]
puts h.fetch("green", nil)

--output:--
nil
nil

As a result, the way you used fetch in your code doesn't do anything
different than the '[]' method would do.

Here's where fetch would make a difference:

h = Hash.new(10)
h["red"] =  2
h["blue"] =  15

puts h["green"]
puts h.fetch("green", nil)

--output:--
10
nil


h = Hash.new
h["red"] =  2
h["blue"] =  15

puts h["green"]
puts h.fetch("green", true)

--output:--
nil
true
7stud -. (Guest)
on 2009-05-04 02:16
7stud -- wrote:
>
> Here's where fetch would make a difference:
>

Or in this case:

Frederick C. wrote:
> or do you sometimes explicitly store nil in
> the session (and want that to be distinct from
> the value not being there at all) ?) ?

h = {"red" => nil, "blue" => true, "yellow" => nil}

puts h.fetch("green", "don't carry that color")


This is where it gets tricky and you have to be a little careful:

h = {"red" => nil, "blue" => true, "yellow" => nil}
result = h.fetch("blue", "don't carry that color")

if result == "dont't cary that color"
  puts "Sorry"
elsif result
  puts "Available"
else
  puts "Out of stock"
end


--output:--
Available
Doug J. (Guest)
on 2009-05-04 02:37
(Received via mailing list)
> As a result, the way you used fetch in your code doesn't do anything
> different than the '[]' method would do.

I've got it! :)  *AND*, I don't have to expand my thinking about
what's true and what's false in Ruby.  What I have to keep in mind is
that hashes return a default value for an undefined key. Unless some
other value for the default was set at the time the hash was created,
the default value is nil.  So, when no default value is explicitly set
at the time the hash is created, there is no real difference between:

if myHash[:akey]

and

if myHash.fetch(:akey,nil)

As I say, I think that I have it! :)

Thanks to all who contributed.

        ... doug
This topic is locked and can not be replied to.