Fetch method of session hash


#1

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

#2

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
@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)


#3

It’s not a hash;

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

 ... doug

#4

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/


#5

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



#6

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

#7

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.



#8

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

#9

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)

  1. 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


#10

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


#11

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

#12

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


#13

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.

  1. Is the value something other than false or nil?

If yes, then the value will evaluate to true in an if statement.


#14

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


#15

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.


#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


#17

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! :slight_smile: 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! :slight_smile:

Thanks to all who contributed.

    ... doug