ESI meets ERB, with some odd results

Hi –

I’ve got some ESI variables in a template, and am trying to assign
their values to Ruby variables. Strangely, it seems to work and not
work at the same time.

Here’s the relevant part of the template, with some comments and
followed by explanation:

esi:vars
<% state = “$(GEO{‘region_code’})” %>
<% city = “$(GEO{‘city’})” %>

State: <%= state %>
# CT
City: <%= city %>
# NEWHAVEN

Massaged city: <%= CITIES[state][city] %> # Uses the literal EIS
strings

</esi:vars>

The CITIES hash provides corrected city names when the ESI value lacks
spaces – so, for example, CITIES[“CT”][“NEWHAVEN”] is “New Haven”.
The state and city variables display correctly in those middle lines
– but when addressing the CITIES hash with those same variables,
they’re evaluated as the literal ESI strings (“$(GEO…”). The
evidence for this is that I’ve seeded the hash:

CITIES[“$(GEO{‘region_code’})”][“$(GEO{‘city’})”] = “KEYING LITERAL
ESI STRINGS”

and that “KEYING…” string appears next to “Massaged city”.

So, strange as it sounds, the variables seem to be differently bound
depending on which line is being evaluated. So far I’ve not been able
to puzzle through the sequence of events in such a way as to come up
with a way to inject the state and city values into a call to the
CITIES hash. I’d be interested in any ideas or solutions people might
have.

David


David A. Black
The Well-Grounded Rubyist – The Well-Grounded Rubyist
The Compleat Rubyist – http://www.compleatrubyist.com

hi david!

David A. Black [2011-07-20 15:24]:

</esi:vars>
well, as far as ruby/erb is concerned there is no ESI, right? it
simply produces:

esi:vars

State: $(GEO{‘region_code’})
City: $(GEO{‘city’})

Massaged city:
whatever-the-value-of-CITIES["$(GEO{‘region_code’})"]["$(GEO{‘city’})"]-is

</esi:vars>

the hash lookup occurs before ESI gets any chance to replace the
variables. so i don’t think there’s any way to achieve what you want
(other than going back to the server by some means after ESI
processing has happened). i’m totally unfamiliar with ESI, though,
so i might be off.

cheers
jens

Hi –

On Wed, Jul 20, 2011 at 11:51 AM, Jens W.
[email protected]wrote:

Massaged city: <%= CITIES[state][city] %> # Uses the literal EIS

What’s odd is that both behaviors seem to happen: the Ruby variables
being
bound to the literal GEO strings, and the Ruby variables being bound to
the
ESI interpolations of those strings. So state and city display as CT and
NEWHAVEN… but when used as hash keys, those same variables behave as
the
literal GEO strings.

We solved the problem by doing it all in JavaScript :slight_smile:

David


The Ruby training with Black/Brown/McAnally
Compleat Stay tuned for next event!
Rubyist http://www.compleatrubyist.com

David Black [2011-07-20 21:08]:

What’s odd is that both behaviors seem to happen: the Ruby
variables being bound to the literal GEO strings, and the Ruby
variables being bound to the ESI interpolations of those strings.
no, it’s not. the ruby variables are replaced with the string values
you initialized them with - in both places. the ESI processing
kicks in after that (it operates on what the application sends as
HTML response; just like SSI in principle). so there’s nothing
unusual going on at all. it’s just that both processors (ruby/erb
and ESI) operate in the opposite order than you seem to have assumed.

but now that you found a different solution this is all moot, of
course :wink:

Hi –

On Wed, Jul 20, 2011 at 3:24 PM, Jens W. [email protected]
wrote:

What I’m not seeing is why this:

CITIES[state][city]

doesn’t undergo the same evaluation/interpolation as this:

<%= state %>

Whatever happens, I would expect “state” to end up representing the same
thing every time, instead of representing the string “CT” at one point
and
the string “$(GEO{‘region_code’})” at another point. Why doesn’t the EIS
processing ensure that we get CITIES[“CT”][“NEWHAVEN”]?

but now that you found a different solution this is all moot, of
course :wink:

True :slight_smile: except I hate letting things slip away without fully
understanding
them.

David

You received this message because you are subscribed to the Google G.
“Ruby on Rails: Talk” group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en.


The Ruby training with Black/Brown/McAnally
Compleat Stay tuned for next event!
Rubyist http://www.compleatrubyist.com

Hi –

On Wed, Jul 20, 2011 at 7:33 PM, Florian Amann
[email protected]wrote:

Hi David,

I’ll describe two scenarios and I hope I can clarify the problem.

[snip explanation]

Thanks for the explanation. I think I was over-thinking (or
under-thinking
:slight_smile: it. In the end I think doing it with JavaScript is indeed a better
way.

David

The Ruby training with Black/Brown/McAnally
Compleat Stay tuned for next event!
Rubyist http://www.compleatrubyist.com

Hi David,

I’ll describe two scenarios and I hope I can clarify the problem.

First of all the Mapping:
BAZ = {
‘GEO_foo’ => { ‘GEO_bar’ => ‘GEO_baz’ },
“$(GEO{foo})” => { “$(GEO{bar})” => ‘KEYING LITERAL ESI STRINGS’ }
}

Second the default order of processing…

  1. source:

<% foo = “$(GEO{‘foo’})” %>
<% bar = “$(GEO{‘bar’})” %>

Foo: <%= foo %>
Bar: <%= bar %>

Baz: <%= BAZ[foo][bar] %>

… up to this point nothing was evaluated.

  1. erb’d:

Foo: $(GEO{‘foo’})
Bar: $(GEO{‘bar’})

Baz: KEYING LITERAL ESI STRINGS

… the time erb evaluates the five expressions the first two assign

their

values, which still contain the ESI instructions. In the following

expressions these instructions are written to the document.

As for the last expression Ruby tries to resolve the key

$(GEO{'foo'}) in

the BAZ hash.

At this time the BAZ hash has no member with this name resulting in

nil

unless otherwise defined.

In the first line you see the assignment I made to produce this -

kinda

unwanted - result.

  1. ESI:

Foo: GEO_foo
Bar: GEO_bar

Baz: KEYING LITERAL ESI STRINGS

Assuming that GEO[‘foo’] contains the string GEO_foo and GEO[‘bar’]

contains

GEO_bar the values are correctly replaced.

But since ‘KEYING LITERAL ESI STRINGS’ is not in any way an esi

instruction

nothing happens here.

snip


So, what happens when we switch 2 and 3? First of all I think this could
either suck performance wise or improve it. I don’t know 'cause I’m not
so
much into socket communication. That aside:

  1. ESI:

<% foo = “GEO_foo” %>
<% bar = “GEO_bar” %>

Foo: <%= foo %>
Bar: <%= bar %>

Baz: <%= BAZ[foo][bar] %>

… the ESI instructions were replaced correctly as intended.

  1. erb’d:

Foo: GEO_foo
Bar: GEO_foo

Baz: GEO_baz

… well, I think this is the result you expected. Mapping is done

correctly, and Foo: & Bar: show the correct values.

snip


Switching step 2 and 3 could be a problem depending on your setup, but
not
impossible. But still I’d not mix two templating engines as I still
think that
it is possible to expose, if not already exposed, the GEO variables to
your
Rack::Request object. They should be members of the #env property. If
not you
could, if you use VCL and the GeoIP library, modify the plugin in a way
it
exposes them.

best
Florian