ODBC app in Ruby - I don't believe it.

D

Dave Howell

The other paradigm that I've tripped over is that I want my models to =
know how to present themselves. Tango did this to a limited extent, and =
I really liked it. I was expecting a beautiful world of =
self-constructing data when I started working with Rails. Something like =
this:

blog.author
}
=3D> "<form action=3D\"/savepost"><input type=3D'text' length=3D'50' =
value=3D'Huffy Angelaton' name=3D'blog.author'></form>"

I found *nothing* that even remotely approached that. So I wrote my own.=20=


There was a pretty long discussion on the Ramaze list about this, =
because I'm well aware that this is a big-time violation of the =
Model-View-Controller idea. Unfortunately, MVC just can't handle this =
without a huge amount of extra lumps of code. Well, it can handle the =
*previous* example. But it really can't handle the following one. Or (to =
inject at least a smidge of humility), I was quite unable to find a way =
to do it.=20

This is a slightly modified example from my working code. A "Batch" is a =
particular batch of manufactured product, specifically an herbal =
medicine. I've obfuscated the UUIDs.=20
b =3D Batch['3705bf0e-4264-6654-ff6c-00065b3f562c']
=3D>#<Batch @values=3D{:wv=3D>"1:1.7", :notes=3D>nil, :active=3D>true, =
:herbpercent=3D>#<BigDecimal:101f28328,'0.0',4(12)>, :pressed=3D>nil, =
:batchcode=3D>"06082030.1", :herbweight=3D>3741, =
:lot_id=3D>"e62b56d2-a741-xxxx-xxxx-xxxxxxxxxxxx", :initvol=3D>6360, =
:created=3D>Fri Aug 04 00:00:00 -0700 2006, :finalvol=3D>8812, =
:extract_id=3D>"f2580cc8-2354-xxxx-xxxx-xxxxxxxxxxxx", =
:batch_id=3D>"3451a2a6-5fc1-xxxx-xxxx-xxxxxxxxxxxx", :id=3D>1534, =
:decocted=3D>false, =
:cultivation_id=3D>"3705ff6c-2355-xxxx-xxxx-xxxxxxxxxxxx"}>

However, a batch also contains multiple non-active ingredients, called =
components.
=3D> [
#<Component =
@values=3D{:percentage=3D>#<BigDecimal:101f220b8,'0.1E2',4(8)>,=20
:batch_id=3D>"3705ff6c-5fc1-xxxx-xxxx-xxxxxxxxxxxx",=20
=
:componentcategory_id=3D>"4ace3c04-2357-xxxx-xxxx-xxxxxxxxxxxx"}>,=20
#<Component =
@values=3D{:percentage=3D>#<BigDecimal:101f21a50,'0.5E2',4(8)>,=20
:batch_id=3D>"3705ff6c-5fc1-xxxx-xxxx-xxxxxxxxxxxx",=20
=
:componentcategory_id=3D>"4ace3f92-2357-xxxx-xxxx-xxxxxxxxxxxx"}>,=20
#<Component =
@values=3D{:percentage=3D>#<BigDecimal:101f21410,'0.4E2',4(8)>,=20
:batch_id=3D>"3705ff6c-5fc1-xxxx-xxxx-xxxxxxxxxxxx",=20
=
:componentcategory_id=3D>"4ace430c-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}>]

And each component, in turn, is linked to a category:
b.components[0].componentcategory
=3D> #<Componentcategory @values=3D{:name=3D>"Glycerine", :sequence=3D>3, =
:componentcategory_id=3D>"4ace3c04-2357-xxxx-xxxx-xxxxxxxxxxxx"}>


If I want to create a form for a user to edit the batch data, what I put =
in my code is this:

e.editform.to_form

and what I get is this:
<input name=3D'batch_id' =
value=3D'3705ff6c-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<select name=3D'cultivation_id' id=3D'Cultivation'>
<option =
value=3D'345183ca-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Other said:
<option selected=3D'true' =
value=3D'3451a2a6-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Organically =
Grown said:
<option =
value=3D'3451a68e-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Wildcrafted said:
<option =
value=3D'3451a9b8-xxxx-xxxx-xxxx-xxxxxxxxxxxx'> said:
<option =
value=3D'3451acd8-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Cultivated said:
<option =
value=3D'3451b08e-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Grown Without =
Chemicals said:
<option =
value=3D'77cc2f7a-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Forest Grown said:
<option =
value=3D'c7406e90-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Wild Simulated said:
</select>
<input name=3D'Component:8313022463:batch_id' =
value=3D'3705ff6c-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<input name=3D'Component:8313022463:componentcategory_id' =
value=3D'4ace3c04-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<select name=3D'Component:8313022463:componentcategory_id' = id=3D'Componentcategory'>
<option =
value=3D'4acb07a0-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Olive Oil said:
<option =
value=3D'4ace354c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Other said:
<option selected=3D'true' =
value=3D'4ace3c04-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Glycerine said:
<option =
value=3D'4ace3f92-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Ethanol said:
<option =
value=3D'4ace430c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Water said:
<input name=3D'Component:8313022463:percentage' size=3D'6' = value=3D'10' type=3D'text'/>
<input name=3D'Component:-7531801290:batch_id' =
value=3D'3705ff6c-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<input name=3D'Component:-7531801290:componentcategory_id' =
value=3D'4ace3f92-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<select name=3D'Component:-7531801290:componentcategory_id' = id=3D'Componentcategory'>
<option =
value=3D'4acb07a0-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Olive Oil said:
<option =
value=3D'4ace354c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Other said:
<option =
value=3D'4ace3c04-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Glycerine said:
<option selected=3D'true' =
value=3D'4ace3f92-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Ethanol said:
<option =
value=3D'4ace430c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Water said:
<input name=3D'Component:-7531801290:percentage' size=3D'6' = value=3D'50' type=3D'text'/>
<input name=3D'Component:-6831266729:batch_id' =
value=3D'3705ff6c-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<input name=3D'Component:-6831266729:componentcategory_id' =
value=3D'4ace430c-xxxx-xxxx-xxxx-xxxxxxxxxxxx' type=3D'hidden'/>
<select name=3D'Component:-6831266729:componentcategory_id' = id=3D'Componentcategory'>
<option =
value=3D'4acb07a0-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Olive Oil said:
<option =
value=3D'4ace354c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Other said:
<option =
value=3D'4ace3c04-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Glycerine said:
<option =
value=3D'4ace3f92-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Ethanol said:
<option selected=3D'true' =
value=3D'4ace430c-xxxx-xxxx-xxxx-xxxxxxxxxxxx'>Water said:
<input name=3D'Component:-6831266729:percentage' size=3D'6' = value=3D'40' type=3D'text'/>
<input name=3D'created' size=3D'12' value=3D'2006 Aug 04' = type=3D'text'/>
<input name=3D'wv' size=3D'40' value=3D'1:1.7' type=3D'text'/>
<input name=3D'herbpercent' size=3D'6' value=3D'0' type=3D'text'/>=
<input name=3D'batchcode' size=3D'40' value=3D'55436476' = type=3D'text'/>
<input name=3D'herbweight' size=3D'7' value=3D'3741' = type=3D'text'/>
<input name=3D'initvol' size=3D'7' value=3D'6360' type=3D'text'/>
<input name=3D'finalvol' size=3D'7' value=3D'8812' type=3D'text'/>=
<input name=3D'decocted' type=3D'checkbox'/><textarea =
name=3D'notes' rows=3D'8' cols=3D'80'> said:
<input checked=3D'' name=3D'active' type=3D'checkbox'/>
<input name=3D'pressed' size=3D'12' value=3D'' type=3D'text'/>"

A batch has more than one component, and each component can be a =
particular substance. In order to present that HTML code, my batch =
object had to know to take its own fields, like "batchcode" and turn =
them in to text input fields. The size of the field is based on how much =
space is reserved in the database itself for that data. Each Component =
of a Batch has to do the same thing. "Percentage" is a text input field =
long enough for the custom data type (a numeric(5,2) that only accepts =
numbers in the range 0.00 to 100.00). But since there are multiple =
components, and HTML forms don't have support for nesting, each form =
field has to get a unique name so that when the data comes back, it's =
possible to figure out which percentage belongs to which component.=20
Finally, each component is linked to a 'Componentcategory." In =
order to allow the user to select a different category, the form has to =
know what EVERY row in the table is, in order to create the list of =
<options>.=20

This last bit is really critical. If you just ask the object itself, it =
cannot tell you what you need to know to create the form.=20
b.components[0].componentcategory
=3D> #<Componentcategory @values=3D{:name=3D>"Glycerine", =
:sequence=3D>3, =
:componentcategory_id=3D>"4ace3c04-2357-xxxx-xxxx-xxxxxxxxxxxx"}>

To find out what other categories this component *could* be, you have to =
back up from this component category to the class, then query for all =
members of the class, then use that information to construct one form =
field, using the identity of the current active *instance* of the class =
to figure out which <option> is marked as "selected".=20

I tried to get to this point with templating, but pretty soon my =
templates were hardly more than <body><@htmlfromcontroller></body>, so =
what's the point?=20

I must admit, I'm still not too sure what paradigm IS behind the current =
flock of templating tools, except that it isn't like this, and doing it =
this way is totally rocking, so I have no incentive to change.=20
 
P

Phillip Gawlowski

My apologies if quoting is mangled, there's only so much I can do
about broken email clients...

I would suggest, however, that the best place to start is to understand that there's a serious problem with the very idea of "legacy"
databases. My database is NOT a legacy database. It's a brand new installation, it's entirely under my control. I am beholden to
nobody. To use the term "legacy" to describe it is extremely misleading. However, I happen to feel that the database itself is the
most well suited component to ensure the integrity of the data, and the more I work with the various Ruby-based widgets, tools, and
libraries, the more I believe this. I will NEVER give my Ruby code or an ORM the ability to alter my DB schema. I also considered
and rejected MySQL as the datastore, because it does not meet my minimum standards for data safety.

Legacy system:

Wikipedia:
"A legacy system is an old technology, computer system, or application
program that continues to be used, typically because it still
functions for the users' needs, even though newer technology or more
efficient methods of performing a task are now available."

ichnet.org:
"Those systems in existence and either deployed or under development
at the start of a modernization program. All legacy systems will be
affected by modernization to a greater or lesser extent. Some systems
will become transition systems before they are retired."

bbn.com:
"A customer's existing system, often a database system."

So, yes, your database is a legacy system, as far as switching horses
(to a very different programming style and methodology for web
development) mid-race is concerned.
You said above that your kneejerk reaction was to "migrate to something sane." We agree that that's not really the right response,
but we might not agree on why. I read the Rails/ActiveRecord documentation with what eventually became horror. MySQL's little
foibles (like silent truncation of over-long strings) were nothing compared to the gaping holes and systemic inadequacies of
ActiveRecord. I assumed at first I was just missing an entire chunk of documentation, the one where it talked about how you could
create foreign key relationships *in the database,* among other things. Instead I found pages of documentation about 'migration,'
where the docs *bragged* about how easy it was to just swap out MySQL for SQLite, or vice versa, because it was supporting only
the least common denominator of functionality from the DB engines.

The least common denominator being, allegedly, the SQL standard. Which
pretty much *no existing SQL database supports in a portable fashion*.
So, what shall be done give that, a) time, b) money, c) knowledge are
in finite supply? ActiveRecord/Rails opted for portability as much as
is possible. Frankly, you can be happy that it is trivial now to
change ActiveRecord for something different and have Rails still work.
I make my database engine work for a living. While it would, in theory, be possible to "migrate" my data from PostgreSQL to Oracle,
SQLServer, or (I suspect) DB2, I believe it would be extremely difficult to replicate the current functionality with MySQL, and utterly
impossible with SQLite. In practice, moving to a new DB store would require a lot of handwork, rewriting various triggers, creating new
ones to replace the custom data types, adding new linking tables to replace the foreign key arrays, and so on. There is no way that it
could be done by generic migration code.

And given that you know how much work you face, how much *DB engine
specific* work at that, you seriously expect a tool to cover every
possible case and usage scenario? That's a rather arrogant attitude at
best.
I eventually found some other blogs wherein people had commented on similar experiences, which was why I wanted to reassure the
original poster that "it wasn't just him not getting it" or some such thing. I knew when I started working on this project that I would find
myself holding some assumptions that were going to trip me up, and I've tried to keep an open mind and learn new ways of doing stuff
and of thinking about stuff. However, building my web apps from a data-centric, and DB-centric, perspective is not going to change, at
least not until some kind of reason for doing so that's a few orders of magnitude more compelling than anything I've seen to date
comes along.

Rails is a result of work done 37signals, derived from the experiences
these people had when creating brand spanking new web applications.
That's the space Rails occupies and, for better or for worse,
dominates.

Rails never was good at being put on top of existing databases or to
fit into existing systems, since that is not the development goal for
Rails.
Templating foundered on more or less the same problem. I first had to 'template' web pages using Microsoft's IDC/HTX system. This
would be what they had *before* they invented Active Server Pages. It was pretty awful. (For one thing, no cookies. Period.) A year or
two later, I went looking for an alternative. I evaluated ASP, WebObjects, SilverStream, and Tango, and Tango blew my socks off. It
did not use templating as such. Each 'page' was an interpreted file, the file contained subunits that would have markup, and then you
could also embed code within the markup material. Not unlike Haml's partials, but it all happened within a single file.

I have the distinct feeling that you are strongly opposed to Java's
"One File, One Class" approach, too.
That was in 1997. I was expecting, upon my return to DB<->web programming, to find things fabulously more advanced. I didn't
expect to find them almost unrecognizable. Unfortunately, the lack of recognition isn't because everything's fabulously more
advanced. There's been a lot of sideways motion.

I can't comment on that, but I doubt that expecting that programming
changed since the last paradigm shift to OOP is an approach that lends
itself to safety (alas). The changes were in methodology, like the
Model-View-Controller pattern, which nicely separates area of
responsibility of code, minimizing dependencies of otherwise unrelated
code.
The tutorial that I kept hoping to find, and that I didn't see *anywhere*, was the one that would start out like "Let's build a blogging
site. Here's the tables we're going to use. Here's the SQL code you would run on your database to create them. Now, run this
magical command and Railamanatra will construct models and web pages and views and stuff to help you get started . . . ." or
maybe "Here's how to convert your current PHP-based blogging site to Railamanatra, without having to alter the existing data or
database."

That's because Rails aims to be all-encompassing. You write everything
you need in one language, instead of having to switch gears going from
Ruby to SQL to HTML. And nobody said that Rails fits your problem
space, either.

Rails is excellent if you can control everything in a project, from DB
schema, to server deployment, to the server's software. It's not a
good tool if you want to make a square peg fit a round hole, however.
So, in a nutshell, there are two paradigms that are pervasive in the current Ruby-tool-for-web community that will tend to make people
who don't share them incredibly miserable. The one I've mostly covered above is the middleware-centric perspective, and it seems
fairly obvious to me this is because most of the current tools were created by people who started with Rails. Rails, as the designers
clearly explain, is "opinionated software." I *like* that. I agree with their idea that there's a lot of merit in making something that does
NOT try to be everything-agnostic, that provides suggestions, guide rails, defaults, and implicit assumptions. However, in this
particular case, MY perspective is that the data is god-like, the DB engine is the emperor, and the middleware are its lackeys and
peons, and Rails really hates that. Alas, all the viable alternatives I found still believe that to one degree or another. I picked Ramaze
in the end because it felt less strongly about that than my other options.

Then don't use Rails. It's as easy as that.
In fact, I think that this 'opinion' is actually quite mild in some of the other platforms; the authors were, in fact, trying to go for a more
generalized approach. But the *documentation* still reflects that original Rails point of view more strongly.

That could be because the Merb and Rails teams (and code) merged
between Rails 2.0 and the current Rails 3.0 release. And as we all
know, the documentation ranks pretty low on teh "things developers do
for fun" scale (much to my own annoyance).
Just figuring out that I had to go shopping for multiple different parts in order to replace what Tango did for me was one unexpected
stumble. When I did, then I realized that, for me, starting with the ORM was absolutely the right thing to do. I had a seriously
complex schema and if my ORM couldn't keep up, it was pretty irrelevant what else I had. And Sequel has outstanding, phenomenal
documentation, and appeared to have a notably data-centric perspective. Once I had that, then I picked out things that went well with
it.

Fortunately, thanks to the middle-ware centric approach, you can
actually exchange these things with relative ease.

Well, to cut a long story short: Don't be surprised that Rails doesn't
fit your problem. Instead of venting about it, move on, and look for
something that fits, or build your own (or fork Rails / the parts of
Rails you like, and build from that). It's open source, nobody'll stop
you.

--
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,734
Latest member
manin

Latest Threads

Top