ramaze and ajax ( Javascript library )

99 views
Skip to first unread message

felipon

unread,
Aug 23, 2010, 9:14:58 PM8/23/10
to Ramaze
Hi,

does Ramaze "support" those javascript libraries in some way ? (those
from website)

Has any helper to generate code for a given library ...

or really it doesn't support any library and one have to deal with
javascript ???

well .. english is not my best language ... i hope not to be too much
confusing .. :-)


thnx.

Lars Olsson

unread,
Aug 24, 2010, 3:41:41 AM8/24/10
to Ramaze
Hi!

Ramaze runs on the server side. Javscript runs on the client. Since
the code is executed in different places they don't interact
"directly". Ramaze will work with *any* AJAX library.

AJAX scripting works by talking to the server using plain HTTP. This
is no different than using a form to send data to the service.

There *might* be some helper that can help generate javascript code in
your view, but I'm not aware of any helper that does this. But
javascript is easy, especially if you use one of the larger toolkits
(like JQuery). Nowadays you don't need to code that much javascript
yourself, it's all in the toolkit! It was a different story in the
middle nineties when you had to do it all by yourself... ;)

/lasso

felipon

unread,
Aug 24, 2010, 11:02:59 AM8/24/10
to Ramaze
hi,

On 24 ago, 03:41, Lars Olsson <la...@lassoweb.se> wrote:
> Hi!
>
> Ramaze runs on the server side. Javscript runs on the client. Since
> the code is executed in different places they don't interact
> "directly". Ramaze will work with *any* AJAX library.
>
> AJAX scripting works by talking to the server using plain HTTP. This
> is no different than using a form to send data to the service.
>

yes i know.

I'm comming from Perl an there is plenty of libraries to do de magic
mapping between javascript and server code, that's why i'm asking.


> There *might* be some helper that can help generate javascript code in
> your view, but I'm not aware of any helper that does this. But
> javascript is easy, especially if you use one of the larger toolkits
> (like JQuery). Nowadays you don't need to code that much javascript
> yourself, it's all in the toolkit! It was a different story in the
> middle nineties when you had to do it all by yourself... ;)
>

Ok. thnx.


by the way, can you point me to some examples to building form with
BlueForm ,,,, i'm very very lost.

Lars Olsson

unread,
Aug 24, 2010, 12:07:58 PM8/24/10
to Ramaze
I've actually never used the BlueForm helper myself. I'm used to
building my forms by hand, but after skimming the docs at
http://github.com/manveru/ramaze/blob/master/lib/ramaze/helper/blue_form.rb
I would say it works something like this:

Controller code:

class MyController < Ramaze::Controller

helper :blue_form # Makes BlueForm methods available to this
controller

def sample_form
form = form(:action => :data_receiver, :method => :post) do |f|
f.text('User name', :user)
f.password('Password', :password)
f.select('Favorite color', :color, ['Red', 'Green', 'Blue'])
f.checkbox('Extra cheese?', :extra_cheese)
end
end

end

View code (using Ezamar engine):
#{form}

Which renders (a very ugly) form. I guess there are tons of options
you can add, but since I prefer to code my forms manually I haven't
looked to closely.

/lasso

Lars Olsson

unread,
Aug 24, 2010, 12:14:28 PM8/24/10
to Ramaze
Whoops...That should of course be @form, not form. Working code:

Controller:

class MyController < Ramaze::Controller

helper :blue_form # Makes BlueForm methods available to this
controller

def sample_form
@form = form(:action => :data_receiver, :method => :post) do |f|
f.text('User name', :user)
f.password('Password', :password)
f.select('Favorite color', :color, ['Red', 'Green', 'Blue'])
f.checkbox('Extra cheese?', :extra_cheese)
end
end

end

View:

#{@form}

/lasso



On 24 Aug, 18:07, Lars Olsson <la...@lassoweb.se> wrote:
> I've actually never used the BlueForm helper myself. I'm used to
> building my forms by hand, but after skimming the docs athttp://github.com/manveru/ramaze/blob/master/lib/ramaze/helper/blue_f...

felipon

unread,
Aug 25, 2010, 5:02:25 PM8/25/10
to Ramaze
Well, that really sucks .... no ofence to the author please, i'ts just
that one need to build menus and composite widgets programatically ...
the standard
CGI library does good work in that respect but it can't be
required ...


i'm getting very frustrated with ramaze's lack of documentation.

:-(

bye.

Lars Olsson

unread,
Aug 26, 2010, 5:54:22 AM8/26/10
to Ramaze
Since I don't know what you are trying to build it's hard to tell
whether Ramaze is suitable for your needs, but I really must say I
think Ramaze is well equipped to deal with almost any problem that
need to be solved in a web application.

Ramaze is an MVC framework. This implies that logic of the application
should be separated from the presentation of the data (and the data
itself). Forms are part of the presentation layer and does not "store"
any data in this model. They are just means to transport data between
the client and the server. What this means is that rendering libraries
working in this model usually do one thing (and one thing only):
Transforming ruby code to (X)HTML. It will not create "widgets" that
you can query for content. The controller actually has *no* clue about
what your view looks like and how it works. It just receives HTTP data
(via GET, POST etc) and reacts to that.

Now, this of course isn't the *only* way building a web framework.
ASP.NET works with "components" and I guess there are other languages
that do this as well. In the ruby world though, the MVC paradigm is
quite strong. I've only tried one other ruby framework that really
deals with components/widgets: Wee (http://rubyforge.org/projects/
wee/). Unfortunately that project seems a little inactive, but I
haven't checked it out lately so I really don't know if it is still
working. Maybe someone else knows about any others?

Yes, Ramaze do lack documentation. There is the "Ramaze Book" (http://
book.ramaze.net/), but that unfortunately just covers the basics. Just
like in most projects, it's more fun to code than to document how
stuff works. I agree that this sometimes leads to frustration, but at
least there is a partial remedy to this. This Google Group! You will
probably always get an answer here and pretty quick too. We're aiming
to be a very friendly community and do not wish too chase anyone away
just because they don't understand some strange aspect of the
framework. If you have questions (or suggestions, or criticism, or
improvements) regarding Ramaze, please share them with the world here
so that we can improve.


Thanks

/lasso

felipon

unread,
Aug 26, 2010, 10:46:52 AM8/26/10
to Ramaze
Thaks for your time. i managed to solve my problem, if you want to
know how http://groups.google.com/group/ramaze/msg/80d2011b10b4806c

i want to bother you a little more :-),,, how can one include a
template inside another ? or do something like @a = render(template)
i've tried render_partial but only works in layouts for me.

cheers.

Lars Olsson

unread,
Aug 26, 2010, 11:51:54 AM8/26/10
to Ramaze
Hi!

I'm not sure what you mean when you say that render partial only works
in layout only...The following works for me:

class MyController < Ramaze::Controller

def include_sample
@text = 'Getting ready to include some juicy stuff...'
end

def included_sample
@text = 'Included juicy stuff'
end

end

And then the views:

include_sample.xhtml
<p>#{@text}</p>
#{render_partial(:included_sample)}

included_sample.xhtml:
<p style='color: red; font-weight: bold;'>#{@text}</p>

If the file you want to include isn't an action, you can also use
render_file which works the same way but takes a file name as an
argument instead.

About the problems with the CGI module: What I think manveru meant was
that the CGI module is already included whenever you run ramaze. For
instance, you can do ::CGI.rfc1123_date(Time.now) without explicitly
require:ing cgi yourself. Rack has already required it. If you want to
access a CGI object (like cgi = ::CGI.new) it seems a little
problematic though...The cgi object is "offline" in that
scenario...But Rack probably already has a cgi object somewhere that
you can access. I have to look that up though.

/lasso



On 26 Aug, 16:46, felipon <felipealvar...@gmail.com> wrote:
> Thaks for your time. i managed to solve my problem, if you want to
> know howhttp://groups.google.com/group/ramaze/msg/80d2011b10b4806c

Dave Howell

unread,
Aug 27, 2010, 8:36:29 PM8/27/10
to ram...@googlegroups.com
>
> On 24 Aug, 17:02, felipon <felipealvar...@gmail.com> wrote:
>> Ok. thnx.
>>
>> by the way, can you point me to some examples to building form with
>> BlueForm ,,,, i'm very very lost.

On Aug 24, 2010, at 9:07 , Lars Olsson wrote:
>
> Which renders (a very ugly) form. I guess there are tons of options
> you can add, but since I prefer to code my forms manually I haven't
> looked to closely.

Felipon, I started by trying to use BlueForm myself, and have scrapped it pretty much for Lars' reason: the form pops out in a big lump, with no way to organize the pieces.

When I first started working with Ramaze, I spent quite a bit of time scratching my head and beating on things with a big code stick. I'm happy to report that, at least for now, things have gotten much smoother.

OTOH, a lot of what I've been doing, I think, is just bypassing large chunks of Ramaze. I've deleted the 'layout' directory entirely. My app is down to "/controller," "/model," "/public," and "/spec." (I have no idea what /spec is for. {shrug})

This past week, I believe I've been merrily desecrating the whole MVC paradigm, since I've been teaching my Sequel data objects to format themselves for web page forms. I spent quite a bit of time trying to find a replacement for BlueForm, but everything I found fell far short of what I expected, and am used to. I figured that the previous system I'd used, which I started working with in 1998, would have been totally superseded by what I could get now, but that doesn't appear to be the case. I blame this "MVC" thing. I'm used to data that is context-aware. If I assign a 2-dimensional array to another variable, I get, well, obviously, a copy or reference to a 2-d array. But if I put that same array into the middle of a web page, the contents would appear in the browser automatically wrapped in <table<tr><td>... formatting.

So here's what I ended up building for myself....

Let's say I have a Product. A particular product has a color, which is actually chosen from the Color table.
p = Product.new
p.description = "Fleece Hoody"
p.color = Color[:description => "blue"]
If I want to let somebody edit the Product data, p.name needs to become
<input type="text" name="description" length="30" value="Fleece Hoody">
and p.color should be a pop-down selection menu:
<select name='color'>
<option value='1'>Red</option>
<option value='2'>Orange</option>
<option value='3'>Blue</option>
</select>


Currently, I handle this as follows:

[in model.rb]
class Product < Sequel::Model
include FormHTML
many_to_one :color
end
class Color < Sequel::Model
def formHTML
out = pit(:select){self.class.select(:id, :description).all.collect do |row|
option = pit(:option){row[:description]}
option.add_attribute("value", row[:id].to_s}
if row[:id] == self[:id] then option.add_attribute(REXML::Attribute.new("checked")) end
option
end}
out.add_attribute("name", self.class.to_s}
end
end


[in my controller]
tbl = table{[
['Product Description ', p.formHTML(:description)],
['Color', p.formHTML(:color)]
]}
tbl.class="list"
pit(:form) do [
{:method => :post, :action=>"save"},
p.formHTML(:id),
tbl,
pit(:input){{:type=> :submit, :value=>"Save Changes",:style=>"margin-right: 4em; margin-top: 1em;"}}
] end

"pit" is short for "page item", and it creates a REXML object: "REXML::Element.new(name.to_s) <= yield(contents)" The "<=" is something I taught REXML; it means 'examine the stuff on the right, and figure out an appropriate 'add_' method to insert it into the left.' 'Table' expects an array of arrays in its block, which it then parcels into the appropriate <td>s and <tr>s. The output (I'm going to simulate this by hand, so it might not be spot-on) is basically

<form method="post" action="save">
<input type="hidden" name="id" value="43253">
<table class="list">
<tr><td>Product Description</td><td><input type="text" name="description" length="30" value="Fleece Hoody"></td><tr>
<tr><td>Color</td><td><select name='color'>
<option value='1'>Red</option>
<option value='2'>Orange</option>
<option value='3'>Blue</option>
</select></td></tr></table>
<input type="submit" value="Save Changes" style="margin-right: 4em; margin-top: 1em;">
</form>

If I tell a data object I want the formHTML for a field that's a primary key, then it gives me the HTML for a hidden input item. Char and Varchars become <input type="text" length="30">, while integers become <input type="text" length="5">. "Color" isn't a field of the Product object's table, it's an association, so my Product asks the Color for *it's* form code, and passes that back.

MVC would suggest I not be teaching my models about how they're supposed to look, but it's simply impossible to programmatically build decent forms without deep understanding of the model, and having the controller isolate them means pages and pages of inefficient 'glue' code, I think. Even the Ruby Object/Sequel Model doesn't really have enough information. It presents "char," "varchar," and "text" types as a Ruby String, but if the underlying database type is "text," then my formHTML is going to be a <textarea> not an <input type="text">, for example.

This is still a work in progress. I think I'll be able to replace the hand coding for list tables like Color with an automatic assembler like Product uses, but I haven't worked on that part yet, for example.

Lars Olsson

unread,
Aug 29, 2010, 5:33:31 AM8/29/10
to Ramaze
Hi!

> OTOH, a lot of what I've been doing, I think, is just bypassing large chunks of Ramaze. I've deleted the 'layout' directory entirely. My app is down to "/controller," "/model," "/public,"  and "/spec." (I have no idea what /spec is for. {shrug})

Layouts is most applicable when having a lot of pages that look mostly
the same. In this case it eases development by avoiding view
duplication, ie you don't have to write the same template over and
over again. If your pages have more differences using layouts just
gets harder and harder (in my opinion). I've scrapped them as well
(for now), but I think I'll try using them again for my next
application. Other alternatives you can use to the same effect are
render_partial and render_file. Using those methods in you view you
can include other actions and files (similar to how you do it in ASP
and PHP).

> This past week, I believe I've been merrily desecrating the whole MVC paradigm, since I've been teaching my Sequel data objects to format themselves for web page forms. I spent quite a bit of time trying to find a replacement for BlueForm, but everything I found fell far short of what I expected, and am used to. I figured that the previous system I'd used, which I started working with in 1998, would have been totally superseded by what I could get now, but that doesn't appear to be the case. I blame this "MVC" thing. I'm used to data that is context-aware. If I assign a 2-dimensional array to another variable, I get, well, obviously, a copy or reference to a 2-d array. But if I put that same array into the middle of a web page, the  contents would appear in the browser automatically wrapped in <table<tr><td>... formatting.

I don't agree that your data should know how to display itself. Let's
say you're having some data describing a financial transaction. You
might want to have different representations (views) of the data for
different purposes. You might want to display it on a web page. You
might want to export it to a spreadshet. The possible "views" of your
data is endless. You *can* tell your data how to look in specific
situations (ie a web page) but that what happens when you want to
expose your data in a new enviroment? You have to teach your *data*
new tricks all over again...

This is true even when we're only writing web applications as well.
Let me share an example from my own site.

I run a blog. The blog contains blog posts. Depending on what role I'm
currently having (author or reader) I want to have a different view on
the data. If I'm he author, I should be able to edit the blog post and
change settings for it. If I'm the reader I should not be able to edit
the post but be able to add a comment. Is it really the responsibility
of the *data* to decide what to display?

Controller code:
# Method that displays and publishes blog posts
def edit_post(post = nil)
@new_post = (post == 'new')
if @new_post
@post = BlogPost.new(:permissions => 0)
else
@post = BlogPost[post.to_i]
end
unless @post.nil?
if request.post?
# Lost of code dealing with publishing the blog post
else
@blog = Blog[BLOG_ID]
@categories = BlogCategory.dataset
@errors = @post.errors
end
else
@blog = Blog[BLOG_ID]
@categories = BlogCategory.dataset.order(:category.asc)
@errors = nil
end
else
respond(nil, 404)
end
end

# Method for displaying a blog post
def view(post = nil)
@post = BlogPost[post.to_i]
unless @post.nil? || !@post.visible?
response['X-Pingback'] =
Lassoweb::WebUtils.create_absolute_uri(XMLRPCController.mapping)
@blog = Blog[BLOG_ID]
@comment = session['comment'] || BlogComment.new
@comment_author = session['comment_author'] ||
BlogCommentAuthor.new(:visibility => 0)
@comment_errors = session['comment_errors'] || nil
session.delete('comment')
session.delete('comment_author')
session.delete('comment_errors')
else
respond(nil, 404)
end
end

I have only removed the blog post publishing code in the sample above.
All other code is running on my site right now. If we boil it down to
the essentials we primarily deal with the following data:

@blog - A Blog object (witch is a Sequel::Model)
@post - A blog post (witch is a Sequel::Model)

So, regardless of whether we want to look at the blog post as a reader
or is trying to edit it as an author the primary job of the controller
is to push data from the (M)odel to the (V)iew. The @blog and @post
objects have no clue on how to display themselves, but *neither* has
the controller. The controller is doing the "(C)ontroller" part
(business logic) in the MVC paradigm. The view is responsible for that
displying part, and in ramaze's case that means the template. So even
if the to actions spit out *exactly* the same @blog and @post objects
they can still look differens because the templates look different.

> Lots of code for transforming data to HTML

I don't think your code violates MVC in any way. You're now teaching
your model how to display itself, your teaching the controller/view
how to display the data. So you're actually doing it the MVC way, even
if you don't think so... ;)

But on to my final point. Why do one want to use such helpers as
BlueForm or SequelForm? What is the purpose? I agree that it sounds
cool to have a system that *automatically* displays whatever data your
model holds, but is that automation really that important?

Let me rephrase that: How often do one *not* know how the data looks?
In most cases the data is known, and even if the data itself is not
known, we can at least make assumptions on which data format it has.
Some more live code (this time from my model):

class Blog < Sequel::Model
self.db = BLOG_DB
self.set_schema do
primary_key :oid
text :blog_title
text :blog_tagline
end
self.create_table unless self.table_exists?
validates_presence_of :blog_title, :message => 'Du måste ange en
titel på bloggen.'
end

I *know* my blog has a title. I *know* my blog has a tagline. Why
should I need to have a whole library figuring out on how to display
the data. I already know how I want to display it.

I guess what I'm trying to say is that even though BlueForm
(,SequelForm, whatever) might have its use cases, I find the most
common case to be that you want to display data that you already know.
No one knows better than me how I want that data displayed and thats
why I never use BlueForm and its ilk. I just code my view to display
the data exactly like I want it. Helpers generating forms just isn't
helpful in that scenario.

*If* you have highly *irregular* data (maybe using some NoSQL lib)
then you might get some benefit from using a form generator. Otherwise
my advice would be: Just skip BlueForm and code it in the view
yourself!


Kind regards

/lasso

Scott LaBounty

unread,
Aug 29, 2010, 9:31:35 AM8/29/10
to ram...@googlegroups.com
Layouts are pretty important if you don't want to be repeating headers and footers in every single page. Here's something I wrote a while back:

http://steamcode.blogspot.com/2009/01/using-pagexhtml.html

on this topic.

Scott


--
You received this message because you are subscribed to the Google Groups "Ramaze" group.
To post to this group, send email to ram...@googlegroups.com.
To unsubscribe from this group, send email to ramaze+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ramaze?hl=en.




--
Scott
http://steamcode.blogspot.com/

Dave Howell

unread,
Aug 29, 2010, 8:35:25 PM8/29/10
to ram...@googlegroups.com

On Aug 29, 2010, at 6:31 , Scott LaBounty wrote:

> Layouts are pretty important if you don't want to be repeating headers and footers in every single page. Here's something I wrote a while back:
>
> http://steamcode.blogspot.com/2009/01/using-pagexhtml.html
>
> on this topic.
>
> Scott

Aha.

I created class WebPage to hold the repeating material. I might go back and look at layouts at some point, but my original problem was the amount of programmatically determined material I use. For example, the title of the page as it appears in the head. Simple assignment to a variable, embed the variable. Ok, fine. Except then I wanted the same thing to appear in a header on the page, with formatting. Now I have to embed some code in the template to show the title in that manner. Many of them made this complicated and cluttered. I think the straw that broke the camel's back was when I need to present *pre-formatted* text, and HAML fought me tooth and nail by escaping my text; thus destroying the formatting.

(If this is unclear, I'm talking about data that includes Linnean names, which need to have parts of them italicized. This means the string that comes from the database looks like "<i>Bryonia cretica</i> L <i>ssp dioica</i>" I've fired three different layout schemes and two different XML-handling gems for aggressively escaping my data, instead of believing me when I would tell them 'It's ALREADY XML data, quit screwing with it.' I finally managed to beat REXML into submission, mostly. Libxml, for example, was far too anal-retentive in this regard.)

So now I'm doing layout by manipulating some arrays and some instance variables of an instance of a web page. I can add stuff to the top of the page at the bottom of my code, or vice versa, I can analyze and/or modify stuff I've already "written" to the page, and don't have to jump back and forth between two files to figure out what my page will look like. I embed the HTML in the Ruby Code, rather than vice versa. I find it much easier to read, although that's in part because I'm minimizing how much HTML has to BE visible in my code in the first place because most of it comes out of my data and goes onto the page with a minimum of glue.

Dave Howell

unread,
Aug 29, 2010, 9:57:37 PM8/29/10
to ram...@googlegroups.com

On Aug 29, 2010, at 2:33 , Lars Olsson wrote:
> I don't agree that your data should know how to display itself.

> The possible "views" of your


> data is endless. You *can* tell your data how to look in specific
> situations (ie a web page) but that what happens when you want to
> expose your data in a new enviroment? You have to teach your *data*
> new tricks all over again...

It is, of course, still also just data. I don't *have* to activate the self-formatting behaviors. However, very few of these 'new environments' are relevant. Please recall that the focus of my effort has been teaching my data how to present itself as part of an HTML <form> . . .</form> environment, which is far more complex. Knowing that it's a String or an Integer isn't remotely adequate to correctly construct the editing field object, especially since many of the pieces of data are actually nothing but id codes providing foreign key linkages to other tables.

> Let me share an example from my own site.
>
> I run a blog. The blog contains blog posts. Depending on what role I'm
> currently having (author or reader) I want to have a different view on
> the data. If I'm he author, I should be able to edit the blog post and
> change settings for it. If I'm the reader I should not be able to edit
> the post but be able to add a comment. Is it really the responsibility
> of the *data* to decide what to display?

My answer would be "that depends." In this case, the data is very simple, the different forms in which it appears are each required on very few pages, and Ruby contains built-in commands that can apply the necessary formatting with very little code, so no, not for this blog.

>> Lots of code for transforming data to HTML
>
> I don't think your code violates MVC in any way. You're now teaching
> your model how to display itself, your teaching the controller/view
> how to display the data. So you're actually doing it the MVC way, even
> if you don't think so... ;)

I don't mind being wrong about that. {chuckle} I don't really feel like I have a solid understanding of that paradigm in the first place.

> I *know* my blog has a title. I *know* my blog has a tagline. Why
> should I need to have a whole library figuring out on how to display
> the data. I already know how I want to display it.

I think the key difference here is, your data is really simple. Your title is an ASCII (or Unicode) string. Your tagline is a string. Ruby has readily available tools for formatting strings.

> I guess what I'm trying to say is that even though BlueForm
> (,SequelForm, whatever) might have its use cases, I find the most
> common case to be that you want to display data that you already know.

Aha, and hmm. I have not taught my data how to simply display itself. What I've been teaching it, is how to wrap itself in the HTML required *for a form*. And some of my data is so much more complex than a string that even the Sequel library can't handle it. (Specifically, i've managed to eliminate at least four linking tables by taking advantage of the fact that Postgres supports an "array" type for a ***column*** of a table, which Sequel returns inadequately as a concatenated string, not as an actual array.)

Here's an actual "object" I'm working with. The company makes botanical medicine. When they made a batch of some particular stuff, they'll take some herb or plant, do things to it, and put the results in jars. This is a Batch in the database. The batch has intrinsic properties like when it was made and how many jars there were. It also gets a human-assigned code number. But that code number isn't very helpful; when the staff interacts with a batch, they're thinking in terms of what plant was used to make it. More accurately, in terms of the standard nomenclature for the plant used, which parts of that plant, and characteristics of the results of processing it.

However, the plant used is NOT intrinsic to the batch. The batch is, in effect, an instance of class Extract, the 'recipe' for that batch. The plants used in that batch came from a Lot, a big box of plant stuff shipped from a supplier. The Extract represents the process used to turn certain PARTS of the plant into medicine. Finally, even the plant does not intrinsically have a name. It has MANY names (current Latin, common name, Family name, USDA code name, obsolete name, misnomers, and more).

So when I display information about a Batch on the Batch information page, one of the things I include is the Extract that this is a batch *of*. To give them some useful way to identify the extract, my list includes the extract's code number, and a textual description, for example, "Tincture of fresh _Crataegus monogyna_ flower and leaf". I will present that same text on the Extract page itself as the title of the page, on the "_Crataegus monogyna_" page as part of the list of extracts made from it, and probably on some report pages yet to be written.

But that information does not exist in that form in the database. The extract could contain multiple herbs, with each plant being used fresh or dried, and with only certain parts used. So there's a linking table between the extracts and the herbs, which in turn has a linking table to the table that lists the possible plant parts that could be used. "Tincture" is a property of the extract (it's a tincture because alcohol is used as the carrying solvent.) "Fresh" is a property of the plant<-->extract link. "_Crataegus monogyna_" is defined by following the plant<-->extract link to the plant, then going to the plant names table, and THEN to the plant name *categories* table to find out which of the plant names is the Primary name. The name may or may not have a formatted version available. The common name of this plant is "hawthorne," and the common name doesn't have a formatted version, because it doesn't need it.

So when I ask the Extract to give me its "name," the model pulls together all that data from all those tables. It formats the 'part' information depending on how many parts there are. If there is a "leaf" part and a "flower" part, I'll see "flower and leaf." But if there's a leaf, a flower, and a fruit, then I get "leaf, flower, and fruit."

Finally, if the Extract's name includes a Linnaean Latin plant name, then instead of a string, myextract.name returns a REXML "span" object that contains the other info.


Now think back to the Form of this extract, which happens to be "Tincture." An Extract has a form, and batches have forms. Products that are made from mixtures of batches also have forms ("Tincture," "Glycerine," "Cream," "Oil," and so on). I have multiple site pages that allow editing these things, and all of them need to let the user choose what form that thing is. THIS is where teaching my data how to self-format is tremendously helpful. I simply include someExtract.plants.each do plant . . . plant.form.html . . . end. The data itself is simply a uuid for that form in the Forms table. But when I ask it for it's editable HTML representation, it returns a REXML <select> object containing <option> objects for EVERY row of the Forms table, with the specific entry that matches the current object sporting the "selected" attribute.

That's a fairly large pile of code to construct the drop-down form component for setting the form, and 'form' is a property of a number of different primary classes in the database.

When I ask for someExtract.plants.parts.html, instead of a <select> object, I get a <table> object that contains a bunch of <checkbox> objects, since the number of parts used is one or more.

In a nutshell, the data that I'm working with aren't things that can be represented by Ruby's standard types. These are relational attribute sets that are properties of multiple classes of objects in the database, and it's *much* easier for me if they can format themselves rather than making me do it over and over again.


=======

I learned a lot from writing this response, not the least of which is that I now have a much better understanding of why Rails was such a frustrating disappointment when I tried to use it for this job. The idea that I could construct my schema from within Ruby (whether using Sequel or ActiveRecord or whatever), and/or *migrate* it to some other arbitrary database, still fills me with mirth.

I do wish that there was an object-oriented database with the maturity of Postgres, SQLServer, Oracle, et. al, but so it goes.

Lars Olsson

unread,
Aug 30, 2010, 3:54:59 AM8/30/10
to Ramaze
Your job seems fascinating :) I can agree to that you're having to
deal with quite complex objects, but there is still a part that I
disagree to.

> Aha, and hmm. I have not taught my data how to simply display itself. What I've been teaching it, is how to wrap itself in the HTML required *for a form*. And some of my data is so much more complex than a string that even the Sequel library can't handle it. (Specifically, i've managed to eliminate at least four linking tables by taking advantage of the fact that Postgres supports an "array" type for a ***column*** of a table, which Sequel returns inadequately as a concatenated string, not as an actual array.)

What is a web page? It's just formatted text. So, regardless if you
have a very simple object (String, Fixnum, Time) or a very complex one
(like in your examples) you are still facing the same job if you want
to display the data on a web page: Transforming the data to strings.
In the end, all that is left *are* simple strings. (Unless you are
feeding a java applet or something with your data).

What I'm simply suggesting is this. Move the generation of HTML to the
view. Just pass your data object (however complex) to the view and do
the generation there. Your controller would simply do:

mycontroller.rb
---------------
class MyController < Ramaze::Controller
def display(id)
@data = get_insanely_complex_data_by_id(id)
end
end

If you need some library to transform your data variable to HTML you
can still do it in the view. Everything thats available to the
controller is also available in the view:

display.html
------------
<html>
<head>
<title></title>
</head>
<body>
<?r transform_my_data_to_pretty_html(@data) ?>
</body>
</html>

This is of course no remedy for your actual problem (displaying
complex data) but it separates to controller from the presentation of
the data.

/lasso

Dave Howell

unread,
Aug 31, 2010, 12:49:22 AM8/31/10
to ram...@googlegroups.com

On Aug 30, 2010, at 0:54 , Lars Olsson wrote:

> Your job seems fascinating :) I can agree to that you're having to
> deal with quite complex objects, but there is still a part that I
> disagree to.

Excellent, and thank you for disagreeing. Or, rather, thank you for taking the time to understand my wordy explanation, and offer thoughtful criticism. I'm sure, one way or another, my code will improve as a result of your comments.

> you are still facing the same job if you want
> to display the data on a web page: Transforming the data to strings.

True.


> What I'm simply suggesting is this. Move the generation of HTML to the
> view. Just pass your data object (however complex) to the view and do
> the generation there. Your controller would simply do:
>
> mycontroller.rb
> ---------------
> class MyController < Ramaze::Controller
> def display(id)
> @data = get_insanely_complex_data_by_id(id)
> end
> end

Hmm. So currently, when my controller wants the data to transform into a series of strings suitable for an HTML form, it calls a method on the Model object. With your snippet, I would instead have the controller call its own 'display' method, and pass, er, pass an ID? Is this functionally similar to just passing the Model object?

So, one way or another, I 'get' my Model object representing some agglomeration of information from the database. This gets assigned to @data.

> If you need some library to transform your data variable to HTML you
> can still do it in the view. Everything thats available to the
> controller is also available in the view:
>
> display.html
> ------------
> <html>
> <head>
> <title></title>
> </head>
> <body>
> <?r transform_my_data_to_pretty_html(@data) ?>
> </body>
> </html>

Hmm. Well, one trivial change would be

> class MyController < Ramaze::Controller
> def display(id)

> @data.push(get_insanely_complex_data_by_id(id))
> end
> end

I'm displaying an indefinite number of objects, depending on the page.


But the heart of the matter is that the reason I put this code in the Model in the first place is because, no matter WHERE I put it, I can't see any way to make it work without crossing the Model/View barrier.

When I ask a Model to give me the formHTML for method :fewbahr, it first has to determine what kind of method :fewbahr is.

def formHTML(field=nil)
if field then
case
when self.class.foreign_keys[field] then
nil

It is possible to ask for the field that contains the ID used by an association. It doesn't make any sense to use it, so no HTML is returned. To reference my earlier example, a Batch has an .extract_id, but normally I would ask for the .extract itself, which is a method Sequel creates as a result of having "many_to_one :extract" in the definition of a Batch.

when self.class.associations.include?(field) then
if self.send(field).respond_to?(:formHTML) then self.associations[field].formHTML end

So if :fewbahr refers to a method representing an associated object, I determine this by asking my Model's class for the list of associations, then asking the associated object if *it* responds to an un-parameterized formHTML command. If it does, then I call it.

when field==self.primary_key then
pit(:input){{:type=>"hidden", :name=>field.to_s, :value=>self[field]}}

I'm using UUIDs instead of the traditional sequential integers as keys for the data in my database. By the time Ruby sees a key, it's just a string.

This is why I didn't see any point to putting this code in the view instead of the model. The view can't possibly hope to format it properly unless it is prepared to pull a lot of information out of the Model. It has to understand Models intimately in order to do this. If I understand MVC correctly, what *ought* to be going on is that the Controller would get the core data from the model, including such information as which parts are primary keys, which are associations, and whether the associated objects should be seen on the page in some way, transform it, then pass it to the view, which would take information like "this string should be hidden, that one should be regular text, this one should appear as part of a group of radio buttons," and in turn, construct the appropriate HTML to instantiate those principles.

If I did do it that way, then, indeed, it would be a pretty clean process to swap out "html" and swap in "Access," or maybe "PDF," or some other front end that could let a user fill out and submit a form back to the Controller. But the cost of that flexibility is having to write the code twice; once to convert the Model's structure to something abstract, and then do it again to make HTML from the abstracted form, and creating forms for this data is currently a huge percentage of the total code body. I just don't expect we're going to need or want alternative front ends for this, and the time required to design the intermediate stage, and write and debug double the code (roughly), seemed far too high for the benefit.

Back to the code, briefly. If :fewbahr turns out to be the name of one of the actual columns/fields of this table in the database, then we need a couple more 'case' statements to figure out what to do.

when self.db_schema[field.to_sym] then
case self.db_schema[field.to_sym][:type]
when :string then if self.db_schema[field.to_sym][:db_type]=="text" then

Ruby calls all the text data "Strings," but the database cares about the difference between short strings, which are represented by "char(n)" and "varchar" types, and large blocks of text, which are type "text". If the database is using a "text" column, then the HTML almost certainly needs to be a <textarea>, instead of an <input type='text'>.

pit(:textarea){ [{:name=>field.to_s, :cols => 80, :rows => 8}, self[field], " "] }
else
pit(:input){{:type=>"text", :size=>30, :name=>field.to_s, :value=>self[field]}}
end
when :integer, :decimal then pit(:input){{:type=>"text", :size=>5, :name=>field.to_s, :value=>self[field].to_i.to_ss}}

I'm probably going to add code that again looks back at the database's original data type. "Numeric" includes a definition of how big the number can be, and it would make sense to make the entry field on the form that size as well.

when :float then pit(:input){{:type=>"text", :size=>15, :name=>field.to_s, :value=>self[field]}}
when :boolean then
ffield = pit(:input){{:type=>"checkbox", :name=>field.to_s}}
if self[field] then ffield.add_attribute("checked", "")end
ffield
when :datetime, :date, :time then pit(:input){{:type=>"text", :size=>12, :name=>field.to_s, :value=>(self[field])?self[field].strftime("%Y %b %d") : "" }}

This code is also likely to change drastically. There *is* some data in my database where the time of day is relevant, although I haven't started coding against that part of the database yet. I think I'd like to make this be drop-down menus for picking the month and day, and possibly the year, at least in some situations, but then I have to convert the bits of data that come back from the form and re-assemble it into a Date.

Last, but certainly not least, is the fact that there's a custom enumerated data type used in the database. The 'hydro' type can have the value "fresh," "dried," or "?". Again, by the time it reaches the Controller, it's just a string. If I were going to make this code universal, I would need to check every field's native database type, and if the result wasn't on a list of known types, try to get the database to tell me if it's an enumerated type, and if so, what the legal values are.
else
case self.db_schema[field.to_sym][:db_type]
when "hydro" then
pit(:select, {:name=>"hydro"}){['fresh', 'dried', '?'].collect do |hy|
pit(:option, {:value=>hy}, (if hy==self.hydro then Selected end)){hy}
end}
end
end
I know. It's a 'case' statement with just one lousy case. The reason it isn't just an ordinary "if" statement is that I'm expecting at some point to add a few more special cases to the list.
end
end
end


Another piece of the puzzle that neither the Model nor the database itself yet understands is that there are basically three different kinds of tables. The ones holding 'real' data, the linking tables used for many_to_many relationships, and the "list" tables that are, in effect, a custom Enumerable data type. Adding, say, "baked" to the list of legal types for "hydro" would require executing SQL code against the database to redefine the type. Adding a new plant part to the list of plant parts available is just a standard insert into the appropriate table. If a table is being used to store a list, then it does not get the above code included in it. Instead, it current gets its own private custom definition of formHTML, The 'forms' table doesn't really have any way to know that other objects in the database can only exist in one form, just as the plantparts table doesn't know that an extract can use multiple parts. As a result, (again, currently, and subject to improvement), there's a custom formHTML method defined on the Form model so that an instance of this table can return HTML that includes the entire table, but with the line that represents itself selected. With plantparts, on the other hand, formHTML is defined on the *class*, because I have to pass it a list of the parts that should be checkmarked in its HTML representation.

Lars Olsson

unread,
Aug 31, 2010, 7:50:40 AM8/31/10
to Ramaze
Hello!

I feel that this discussion has started to drift away quite a bit from
the original question. Maybe we should start a new thread? In any
case, I feel that what we are essentially in agreement, but I still
wanted to provide some explanations for my reasoning. Below you will
find some of my thoughts on the MVC paradigm and how Ramaze implements
it. Since I haven't been contributing much to Ramaze (just some tiny
patches long ago) I might be completely wrong, but since my model
seems to fit with Ramaze pretty easily I don't think I'm too far off.
Any one that might have better insigt - feel free to join in to
correct me!

The first question I want to ask is: What is MVC? Here is my
definitions of the different parts:

(M)odel
=======
The model represents the "meaningful data" I want to use in my
application. The data can be of any form. Simple string and numbers
can be data, complex blobs from a database can be data. However, I
usually don't include "metadata" such as how to display the data in my
definition of the model. That's why i really don't like methods like
to_html or to_pdf being added to the model. For me, such metadata does
not belong to the model, it belongs to the view.

(V)iew
======
The main concern of the view is how to "represent" data. The view is
responsible for the actual "rendering" of the data. It can be a web
page, a PDF file or any other format one may ever dream of. The
important thing is: The *same* data can be represented by *different*
views. This implies that the data should *not* carry it's own
representation but instead leave that to the view(s).

(C)ontroller
============
The controller is the "driver" of the application. The controller is
reponsible for the "logic" of the application. What user should be
allowed to see what data? what data is available at this time? Is this
is GET or a post request? One thing the controller also should do
(IMO) is to "pass" the data from the model to the view. In most cases
it *is* possible to dump the data of the model directly into the view,
but that should not be done. The view should be as "stupid" as
possible and just "take orders" from the controller.

Now on to the question on how these definitions fit on Ramaze.

(Model)
=======
Ramaze really does not have any predefined model. No class in the
Ramaze namespace represents a data model. Ramaze can use any data as a
model and that has both advantages and disadvantages. The good thing
is that you can choose your own data dependecies very easily. Ramaze
can use any library (Sequel, DataMapper etc) without bringing stuff in
that you really don't use. You can compare this situation with Rails,
which has a *very* large dependency on ActiveRecord (at least last
time I looked). So when you want to use Sequel in Rails, you still
have to have that enormous library that essentially do the same thing
loaded. In Ramaze you a much smaller list of dependencies and can
choose your data model any way you want.

The disadvantage is of course that it is hard for Ramaze so handle
your data "automatically". We have been discussing it earlier, but
just look how difficult it is to set up scaffolding in Ramaze compared
to Rails.

I *really* prefer the approach Ramaze is taking. Let *me* decide on
how the data should be modeled.

(V)iew
======
Here's a little secret: Ramaze has no views! Well, actually it does,
but if you look in the source code you will see that Ramaze::View does
not do a lot by itself. The main work is instead done by the different
"engines" that Ramaze provides (Etanni, Haml etc). And the engines are
tied to the controller, not the view. Views aren't really independant
objects in Ramaze IMO.

What Ramaze really does when a view is rendered is this:
1) The controller calls the action (public method in controller, ie
index) . Now the controller has the data (stored in instance
variables).
2) The controller calls the engine with the collected variables, a
layout (if defined) and the desired template name.
3) The engine compiles the variables, the layout and the template into
a string
4) The string is returned to the browser (after it goes through the
rest of the Rack middleware)

So, in Ramaze the View part is actually performed by the controller.
At first this was very confusing to me, but then I realized that it
really was quite a clean solution. The controller already has the data
and a separate view object really isn't necessary. This of course
violates the MVC paradigm a bit, but since it all happens behind the
scenes you don't need to care as an application developer.

(And as a added bonus, *all* methods of your controller is available
in your templates. Even private ones. If you ever use self.inspect in
a template, you'll notice that self actually *is* the controller.)

(C)ontroller
============
The controller is the most important piece in any Ramaze application.
The controller controls its own mountpoint, controls the engine (that
renders views), what layout(s) should be used, what functionality that
is exposed to the templates (which helpers are loaded) and everything
else that has to do with the actual request (authentication, request
method and so on). In other words, the controller in Ramaze does a
lot, even more than is suggested by a "pure" MVC model. This is
usually just beneficial, but also leads to a potential problem. People
(including myself) tend to do things in the controller that really
should be done in the view (template). Like I said before, in Ramaze
those two are technically the same object, but that does mean
everything goes "conceptually". To be more specific, methods that
"render" stuff should ideally be in the template, not the controller.
IMO, the only reason *not* to place rendering in the view is when you
don't use a template (like generating an image via RMagick). The gain
of separating the rendering from the actual "application logic" is
that it makes the application logic much more readable and
*independant* from the rendering. If you suddenly find yourself
needing a new "representation" of your data (say, via PDF) you *don't*
need to change your application logic, you just need to add another
view.

Conclusion
==========
Like I said before, I don't pretend to be a Ramaze guru, but I've used
the framework for a long time. My understanding of the inner workings
of Ramaze may be or not be true, but it has served me well when using
Ramaze so far. So, here are my final suggestions on using Ramaze as a
MVC framework.

(M)odel
=======
Always keep your models "clean". Never include metadata that describes
on how to "render" the actual data. The model should only contain the
"actual" data, nothing more.

(V)iew
======
The view should be responsible for rendering data *only*. It should
not contain application logic or fetch data from the model directly.
The *only* kind of code allowed in a view (template) should be
variables and methods that *render* data. "Presentation logic", ie
if's and loops are ok, provided that the only job they do is render
data.

Final example
=============
Here comes a final example that demonstrates my conclusions above:

file: model/mymodel.rb
----------------------
# MyModel contain only "pure" data
class MyModel
attr_accessor :name, :children
def initialize(name = nil, children = [])
@name = name
@children = children
end
end

file: controller/mycontroller.rb
--------------------------------
require_relative '../model/mymodel' # I'm running ruby 1.9.2 - current
dir is not included in default require path anymore
class MyController < Ramaze::Controller
map '/mycontroller'
def index
# The controller doesn't do any rendering. It only passes the data
to the view
@data = MyModel.new('Sam', ['Joe', 'Hannah', 'Elias'])
end
end


file: view/mycontroller/index.xhtml
-----------------------------------
<!-- The view renders the data. Logic is ok, but only if it affects
rendering -->
<html>
<head>
<title></title>
</head>
<body>
<?r unless @data.name.nil? ?>
Name: #{@data.name}
<br/>
<?r end ?>
<?r unless @data.children.empty? ?>
Children:
<br/>
<?r @data.children.each do |child| ?>
#{child}
<br/>
<?r end ?>
<?r else ?>
No children
<?r end ?>
</body>
</html>

I'm looking forward to further discussions.

/lasso

Dave Howell

unread,
Aug 31, 2010, 9:44:34 PM8/31/10
to ram...@googlegroups.com

On Aug 31, 2010, at 4:50 , Lars Olsson wrote:

> Hello!
>
> I feel that this discussion has started to drift away quite a bit from
> the original question. Maybe we should start a new thread?

Well, I've already renamed it once. I think you're right, so I'll rename it again. Renaming vs. starting a new thread means people who are trying to follow it, or trying to NOT follow it, can continue to do so. (For example, if/when this whole thing gets archived on one of those sites, and somebody clicks "next message in thread.")

[definition of MVC elided]

Yea, I completely agree with that.

> Now on to the question on how these definitions fit on Ramaze.
>
> (Model)
> =======
> Ramaze really does not have any predefined model.

Right. This definitely threw me when I first tried to replace Tango. Tango had an IDE, and embodied the database/ODBC connector, the general processing language, and handled rendering. Apache handed a query to Tango, and got back HTML to send to the user. I was rather dismayed when I found that all of the 'modern' Ruby-based tools were more like an old-fashioned Chinese menu. "Select an item from column A, one from B," and so on.

Eventually I figured out I needed to pick my data-object-widget (ActiveRecord, Sequel, etc.), my overall managing framework (Rails, Ramaze, Nitro, Wee, Sinatra, IOWA, and on and on and on), my templating engine (HAML, or, geez, I don't even remember all the ones I looked at), and possibly other bits.

OK, in the end, I have to agree this is probably a good thing. It was just a real head-scratcher to start.

> I *really* prefer the approach Ramaze is taking. Let *me* decide on
> how the data should be modeled.

I am willing to bet that YOU do not appreciate Ramaze's model-neutrality as much as *I* do. {laugh} Even Sequel has made some assumptions about my data that aren't true, and it is *so* much less prone to assumptions than pretty much every other data object modeler I looked at. {shudder}

> (V)iew
> ======
> Here's a little secret: Ramaze has no views! Well, actually it does,
> but if you look in the source code you will see that Ramaze::View does
> not do a lot by itself. The main work is instead done by the different
> "engines" that Ramaze provides (Etanni, Haml etc). And the engines are
> tied to the controller, not the view. Views aren't really independant
> objects in Ramaze IMO.

I'm not entirely sure I understand this. M, V, and C are conceptual models, not physical ones. I mean, it's all in Ruby in the end. What makes a particular pile of code more or less in line with the MVC paradigm is the degree to which the final appearance of the data is separated from the management from the storage. Maybe it depends on what you're defining as "the view?" I suppose one *could* use the image presented in a browser window, for example. I tend to work backwards, and include the stream of HTML that is ready to be shipped across the network as the *product* of the 'view'.

> What Ramaze really does when a view is rendered is this:
> 1) The controller calls the action (public method in controller, ie
> index) . Now the controller has the data (stored in instance
> variables).
> 2) The controller calls the engine with the collected variables, a
> layout (if defined) and the desired template name.
> 3) The engine compiles the variables, the layout and the template into
> a string
> 4) The string is returned to the browser (after it goes through the
> rest of the Rack middleware)
>
> So, in Ramaze the View part is actually performed by the controller.

{scratch head} I think there's still an implied view "place" that doesn't match mine.

Both models and views almost require transformations. My "model" is both what's in Postgres, and what's in my "model.rb" file. The model.rb file, which mostly makes calls to things in the Sequel library, transforms the data in Postgres. It rearranges it, reorganizes it, changes the types, and such. I still include all that in the "M" section, not the "C" section.

Ideally, the Controller would never have to *do* anything, as such, to the data from the models. It would look at it, and based upon information in the model, and information coming from the view (e.g. what link somebody clicked on), it would decide which parts of the Model to pass to the View, possibly with additional semantic information. In other words, "Here are five blog entries. The first one is the featured item, and the other four should be considered comments on it."

The view then has more transformations to handle. A blog entry has a title, and an author, and a body, and whatever else. If it's a main one, maybe there's some bolding, or it goes at the top, or it gets a green back ground. Whatever. So it might throw away some of the data passed to it, create a bunch more information (probably markup related), and rearrange some of the rest, then ship THAT off to Acrobat, or the web server, or a printer.

> At first this was very confusing to me, but then I realized that it
> really was quite a clean solution. The controller already has the data
> and a separate view object really isn't necessary. This of course
> violates the MVC paradigm a bit, but since it all happens behind the
> scenes you don't need to care as an application developer.

Hmm. Yea, I'm still not sure what "a separate view object" would look like. It seems to me that the engine, and the stylesheet, embody the view.

> People
> (including myself) tend to do things in the controller that really
> should be done in the view (template). Like I said before, in Ramaze
> those two are technically the same object, but that does mean
> everything goes "conceptually". To be more specific, methods that
> "render" stuff should ideally be in the template, not the controller.
> IMO, the only reason *not* to place rendering in the view is when you
> don't use a template (like generating an image via RMagick).

Methods that render stuff should be in the view. Which pretty much means that any method that's doing controller-y things shouldn't also be doing view-y things. I don't see any problem with having a single class with both the controller methods and the view methods, as long as they're separate methods. If you could an OtherView module into the class and complete change the appearance and output of the data without altering the controller logic, then the Controller and View are indeed separate, even though the code for them both is in the same class in the same file.

The view might or might not have some kind of template, or Template. A view has to have *some* kind of structural skeleton into which the data will be assembled, but that doesn't necessarily mean it's going to go looking for a particular file in the /templates folder, and use it like some kind of 'fill in the blank' guideline. If that's what you mean when you say 'template,' then I would assert that you should NEVER have methods in the template. The data should be transformed by the view before the view inserts it into the template. I have never seen a scheme for mixing them together that didn't rapidly become illegible.

That is no small part of why I abandoned using a templating engine as part of my view. As much as possible, I'm trying to put the "view" into the CSS file. I'm still doing things like putting <table><tr>...</table> text around data in non-view areas of my code, but I'm NOT saying <table align="center" border="1" color="green"><tr size="+20%">... Thus, a lot of the code to create the final appearance is in the CSS file. It's a major part of my view

I completely agree with your conclusion, in general. Dividing a program into a Model, a Controller, and a View makes it much easier to replace or expand the program's function in the long run. And that's why when I posted my reply to, oh, heavens, whoever asked about Ajax way back when, I said "but I'm pretty sure my solution isn't MVC compliant."

My contention has never been that there aren't very good reasons to use the MVC model. My contention has been that, in my particular case, it's too expensive for the benefit.

If I were to enforce strict isolation between M and V in my situation, then the only way that the View can properly build a form for editing a Batch is if the data passed to it included all the data of the extract that the Batch is a batch of, the plants represented in that extract, the parts of the plant used for each plant, *and the complete list of all possible plant parts*, because with out that last item, the view cannot render a selection list for the user to add or subtract parts.

Remember, what parts of a plant are NOT being used is not part of the Sequel object, but my Model code is "closest" to being able to get that information, because it already has objects at hand that can pull other data from the database. The View, on the other hand, does not (and really should not) have any direct access to Postgres.

The Controller could, I suppose, acquire some of this information from the Model and provide it to the View as part of the initialization of the whole system. "Dear View, here's some data you'll need later on for rendering stuff." But I really want my final output to be fresh and up to date, so what I would have to give my View was an object that embodied a live view into the database.

At this point, it's gotten so preposterously complicated, that I can't imagine actually gaining more benefit than the cost for maintaining MVC separation.

Now, I'm *not* overriding any of the model's regular methods. So just as currently the Models have gained a .formHTML method, they could also get a .formPDF method, or a .formCocoa method (if I wanted to create a native OSX app). And, a lot of the code for .formHTML is in my FormFields module. If I can figure out how to move all of the code into the module, then I would maintain that I have, in fact, effectively maintained MVC isolation. I could replace the code in my Formfields module and completely change the way forms are presented without needing to rewrite any of the controller or model code. The fact that the Formfields module is being included into Model objects instead of some other object is a red herring.


Lars Olsson

unread,
Sep 1, 2010, 2:26:53 PM9/1/10
to Ramaze
Hello again!

I'm sorry I'll have to be a bit short today, but vacation is over... :
(

> I'm not entirely sure I understand this. M, V, and C are conceptual models, not physical ones. I mean, it's all in Ruby in the end. What makes a particular pile of code more or less in line with the MVC paradigm is the degree to which the final appearance of the data is separated from the management from the storage. Maybe it depends on what you're defining as "the view?" I suppose one *could* use the image presented in a browser window, for example. I tend to work backwards, and include the stream of HTML that is ready to be shipped across the network as the *product* of the 'view'.

Of course it's just a conceptual model. I'm very pleased with how
Ramaze works. However, I still think ruby is flexible enough to
combine the pieces in the model into a different, more "pure MVC"
form.

Even though it may be more beneficial to let the controller play both
the V and the C part (as today) I could suggest an alternative
approach. Lets beef up the "View" object:

module Ramaze
class View
attr_accessor :engine # What engine should render the view
attr_accessor :layout # The layout, currently residing in the
controller
attr_accessor :template # What template should be used. I don't
know exactlty where this is stored today

def initialize(engine = nil, layout = nil, template = nil
@engine = engine
@layout = layout
@template = template
end

def render(data)
# Render this view (esentially returning "compiled" output
# The output could be of any form, HTML, PDF or whatever
# data would contain all data that is stored in the controllers
instance variables today
end
end
end

This kind of view could exist *independently* of any controller,
meaning that a single view can be shared by multiple controllers. The
render method would return the actual result of the rendering.

Using this kind of class would also make it easier using different
engines and layouts for different actions in the same controller,
since those attributes don't belong to the controller anymore.

Of course this means we must instead add some mechanism for connecting
the view to a particular action in the controller. Perhaps we could
add:

class Ramaze::Controller
def view(action, view)
actions[action] = view # The actions method is just made up.
# The view variable would be a Ramaze::View
object
# If you want shared views, just create it
outside the controller
end
end

> Both models and views almost require transformations. My "model" is both what's in Postgres, and what's in my "model.rb" file. The model.rb file, which mostly makes calls to things in the Sequel library, transforms the data in Postgres. It rearranges it, reorganizes it, changes the types, and such. I still include all that in the "M" section, not the "C" section.

Your of course right about the need for "transformation", but I don't
think random bytes from any source could be said to constitute a
model. Ruby objects talk to ruby objects and you can't really call it
a model until it has reached it's final phase (as ruby objects).

> Ideally, the Controller would never have to *do* anything, as such, to the data from the models. It would look at it, and based upon information in the model, and information coming from the view (e.g. what link somebody clicked on), it would decide which parts of the Model to pass to the View, possibly with additional semantic information. In other words, "Here are five blog entries. The first one is the featured item, and the other four should be considered comments on it."

I totally agree with this.

> The view then has more transformations to handle. A blog entry has a title, and an author, and a body, and whatever else. If it's a main one, maybe there's some bolding, or it goes at the top, or it gets a green back ground. Whatever. So it might throw away some of the data passed to it, create a bunch more information (probably markup related), and rearrange some of the rest, then ship THAT off to Acrobat, or the web server, or a printer.

That's what I'm suggesting, yes.

> Hmm. Yea, I'm still not sure what "a separate view object" would look like. It seems to me that the engine, and the stylesheet, embody the view.

Yes, and the layout (if one uses that). But today these things are
part of the controller. That is "wrong" in my opinion if one wants to
do "pure" MVC. The views should be independent of the controller (see
above).

> Methods that render stuff should be in the view. Which pretty much means that any method that's doing controller-y things shouldn't also be doing view-y things. I don't see any problem with having a single class with both the controller methods and the view methods, as long as they're separate methods. If you could an OtherView module into the class and complete change the appearance and output of the data without altering the controller logic, then the Controller and View are indeed separate, even though the code for them both is in the same class in the same file.

I'd like to reiterate that I don't see anything wrong with Ramaze's
implementation. It just *feels* like it is violating some principles
of MVC.

> The view might or might not have some kind of template, or Template. A view has to have *some* kind of structural skeleton into which the data will be assembled, but that doesn't necessarily mean it's going to go looking for a particular file in the /templates folder, and use it like some kind of 'fill in the blank' guideline. If that's what you mean when you say 'template,' then I would assert that you should NEVER have methods in the template. The data should be transformed by the view before the view inserts it into the template. I have never seen a scheme for mixing them together that didn't rapidly become illegible.

Views don't require templates. It would be perfectly sensible to have
a View object that dismisses templates completely. What I'm suggesting
is that a view should have a render method. That method would call the
engine and might also call the layout and a template. Depending on the
engine, templates might not be supported. Or the layout could be nil.
Or the template. In those cases the render method would just return
data *without* wrapping it in a template. Just like the controller is
doing today.

> That is no small part of why I abandoned using a templating engine as part of my view. As much as possible, I'm trying to put the "view" into the CSS file. I'm still doing things like putting <table><tr>...</table> text around data in non-view areas of my code, but I'm NOT saying <table align="center" border="1" color="green"><tr size="+20%">... Thus, a lot of the code to create the final appearance is in the CSS file. It's a major part of my view

Regardless of whether Ramaze provided "beefed up" views or not you
could still write your custom *engine* if you have specific
requirements about the output. Just because Ramaze's current engines
specializes in transforming generic ruby variables into HTML does not
mean you cannot write your own to provide a more specific output. (You
still would need a "beefed up" view object if you wanted to mix
different engines in the same controller though...)

> If I were to enforce strict isolation between M and V in my situation, then the only way that the View can properly build a form for editing a Batch is if the data passed to it included all the data of the extract that the Batch is a batch of, the plants represented in that extract, the parts of the plant used for each plant, *and the complete list of all possible plant parts*, because with out that last item, the view cannot render a selection list for the user to add or subtract parts.
>
> Remember, what parts of a plant are NOT being used is not part of the Sequel object, but my Model code is "closest" to being able to get that information, because it already has objects at hand that can pull other data from the database. The View, on the other hand, does not (and really should not) have any direct access to Postgres.

Are you saying that it is not possible to alter the model so that it
only contains the relevant data? A Sequel::Model is only a object, if
necessary you can always wrap it in another object that returns "only"
the data you want. Data can be molded any way to create the model
*you* want.

> The Controller could, I suppose, acquire some of this information from the Model and provide it to the View as part of the initialization of the whole system. "Dear View, here's some data you'll need later on for rendering stuff."  But I really want my final output to be fresh and up to date, so what I would have to give my View was an object that embodied a live view into the database.

I'm not sure I understand this. The controller pulls data "live" from
the model. Why does it need to be pre-initialized?

> At this point, it's gotten so preposterously complicated, that I can't imagine actually gaining more benefit than the cost for maintaining MVC separation.

I agree to that too. One should always work in ways that feel the most
comfortable. Doing the "Right Thing" for its own sake will never work
out in the long run.

/lasso

Michael Fellinger

unread,
Sep 1, 2010, 2:31:52 PM9/1/10
to ram...@googlegroups.com

You almost got it right :)
Controller doesn't handle rendering anymore, that's been moved into
Action a few years ago.

http://doc.rubyists.com/ramaze%2binnate/Innate/Action.html
http://github.com/Ramaze/innate/blob/master/lib/innate/action.rb
http://github.com/Ramaze/innate/blob/master/lib/innate/node.rb#L368

--
Michael Fellinger
CTO, The Rubyists, LLC

Lars Olsson

unread,
Sep 1, 2010, 3:01:38 PM9/1/10
to Ramaze
I knew I had to be wrong somewhere... ;)

But that last link suggests that Action is pretty much tied to the
controller, right? Is it possible to have "free" actions that you can
use in multiple controllers?

/lasso
> http://doc.rubyists.com/ramaze%2binnate/Innate/Action.htmlhttp://github.com/Ramaze/innate/blob/master/lib/innate/action.rbhttp://github.com/Ramaze/innate/blob/master/lib/innate/node.rb#L368

Dave Howell

unread,
Sep 1, 2010, 11:41:12 PM9/1/10
to ram...@googlegroups.com

On Sep 1, 2010, at 11:26 , Lars Olsson wrote:

>>
>> Remember, what parts of a plant are NOT being used is not part of the Sequel object, but my Model code is "closest" to being able to get that information, because it already has objects at hand that can pull other data from the database. The View, on the other hand, does not (and really should not) have any direct access to Postgres.
>
> Are you saying that it is not possible to alter the model so that it
> only contains the relevant data? A Sequel::Model is only a object, if
> necessary you can always wrap it in another object that returns "only"
> the data you want. Data can be molded any way to create the model
> *you* want.

It's not a matter of "only." I have to access *extra* information in order for a view to be able to work. It's not enough to know that this particular component uses the leaves and flowers of a plant. "Leaves" and "flowers" are two members of the set "parts of a plant," and my view needs to know *every* member of that set in order to construct a form.

>> The Controller could, I suppose, acquire some of this information from the Model and provide it to the View as part of the initialization of the whole system. "Dear View, here's some data you'll need later on for rendering stuff." But I really want my final output to be fresh and up to date, so what I would have to give my View was an object that embodied a live view into the database.
>
> I'm not sure I understand this. The controller pulls data "live" from
> the model. Why does it need to be pre-initialized?

Not the controller. The view. The view would need to be given information like "the complete membership of the set of plant parts," and "the complete membership of the set of product forms," and so on.

Lars Olsson

unread,
Sep 2, 2010, 6:21:08 AM9/2/10
to Ramaze
> > Are you saying that it is not possible to alter the model so that it
> > only contains the relevant data? A Sequel::Model is only a object, if
> > necessary you can always wrap it in another object that returns "only"
> > the data you want. Data can be molded any way to create the model
> > *you* want.
>
> It's not a matter of "only." I have to access *extra* information in order for a view to be able to work. It's not enough to know that this particular component uses the leaves and flowers of a plant. "Leaves" and "flowers" are two members of the set "parts of a plant," and my view needs to know *every* member of that set in order to construct a form.

Then the whole set *is* your model. I was under the impression that
you wanted to reduce the amount of data because you didn't use all
data contained in your Sequel::Model objects. But if you need all of
that data you cannot reduce it. You cannot remove things you need in
the view.

> >> The Controller could, I suppose, acquire some of this information from the Model and provide it to the View as part of the initialization of the whole system. "Dear View, here's some data you'll need later on for rendering stuff."  But I really want my final output to be fresh and up to date, so what I would have to give my View was an object that embodied a live view into the database.
>
> > I'm not sure I understand this. The controller pulls data "live" from
> > the model. Why does it need to be pre-initialized?
>
> Not the controller. The view. The view would need to be given information like "the complete membership of the set of plant parts," and "the complete membership of the set of product forms," and so on.

I'm sorry, but I still don't get it. It doesn't matter in which part
the rendering occurs, the data would still be "live" anyway. Why would
the view need to know the data long before it is rendered?

/lasso

Dave Howell

unread,
Sep 2, 2010, 3:10:09 PM9/2/10
to ram...@googlegroups.com

On Sep 2, 2010, at 3:21 , Lars Olsson wrote:

>> It's not a matter of "only." I have to access *extra* information in order for a view to be able to work. It's not enough to know that this particular component uses the leaves and flowers of a plant. "Leaves" and "flowers" are two members of the set "parts of a plant," and my view needs to know *every* member of that set in order to construct a form.
>
> Then the whole set *is* your model.

Yes, but I don't generally want to have to hand the *entire* model to the view every time something happens.

>>> I'm not sure I understand this. The controller pulls data "live" from
>>> the model. Why does it need to be pre-initialized?
>>
>> Not the controller. The view. The view would need to be given information like "the complete membership of the set of plant parts," and "the complete membership of the set of product forms," and so on.
>
> I'm sorry, but I still don't get it. It doesn't matter in which part
> the rendering occurs, the data would still be "live" anyway. Why would
> the view need to know the data long before it is rendered?

Let's create a model of people. There are lots and lots of people. Somebody wants to get information about one of them. So my controller takes data about Fred, and passes it to the view. The data includes his name, his eye color, and what he's wearing.

Now, if the view's job is to create a form for editing details about Fred, then a text entry point is fine for the name. But in order to allow editing about eye color, just knowing Fred's eye color is not enough. The view has to know every member of the set Eye Color, in order to construct the pop-down menu. Likewise, it needs to know the full membership of Clothing, or it can't give the user the option to add a hoodie to the pants that Fred has on.

If I were going to go back and rewrite my code, after this discussion, I might do it so that an instance of a primary object Model like a person, with the attached secondary object instances like Clothing and Eye Color, would also include methods for determining the full membership of the set to which a secondary instance belonged. That would let the View do the actual HTML conversion. Well, basically, that's what I did, except that the new methods don't return an abstracted list of objects for the View to use, they return REXML objects intended to be directly included on the web page.


Hmmm.


I know when I was looking at the various templating engines, Haml impressed me as the only one that seemed to actually be *doing* anything significant. All the rest were various trivial variations of the old-fashioned server side include. Still, looking back at it now, what Haml does is, for my purposes, 'too little, too late.' It provides an elegant way of describing a page of HTML, but I expect my view to build the d*** page on its own, without me having to tell it when to use a list, and what form fields to use for which objects.

So if I were going to implement my current system as a more general-purpose, and more MVC-compliant, tool, I would have to provide extensions to Sequel to simplify which database tables were set lists (Sequel already has tools for identifying linking tables), and would have to construct some kind of transformation module for the view side to convert those abstract objects into display code, whether that code was HTML, or REXML objects, or Haml, or whatever.

Well, I definitely do not understand the 'view' side of Ramaze well enough to try that yet, and it isn't clear to me if anybody else would really care even if I did. {chuckle} As Lars noted a few days ago, it would seem that the data structures I work with are quite a bit more complex than what most people are dealing with; maybe simple templating is entirely adequate for most people's needs. {shrug}


Scott LaBounty

unread,
Sep 2, 2010, 3:44:34 PM9/2/10
to ram...@googlegroups.com
Maybe I'm missing something, but let's look at your Fred, eye color, clothing example. I'm going to assume that there's a people table in the database where you'd do something like:

@fred = People.find(:name => 'fred')

and an eye color database and you'd want all of the eye colors:

@eye_colors = EyeColor.all

and a Clothes table:

@clothes = Clothes.all

then all three variables with all the information you need is available for the view. The above would of course be done in a method in the controller.

Am I missing something here?

Scott

--
You received this message because you are subscribed to the Google Groups "Ramaze" group.
To post to this group, send email to ram...@googlegroups.com.
To unsubscribe from this group, send email to ramaze+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ramaze?hl=en.




--
Scott
http://steamcode.blogspot.com/

Dave Howell

unread,
Sep 2, 2010, 8:27:13 PM9/2/10
to ram...@googlegroups.com

On Sep 2, 2010, at 12:44 , Scott LaBounty wrote:

> Maybe I'm missing something, but let's look at your Fred, eye color, clothing example. I'm going to assume that there's a people table in the database where you'd do something like:
>
> @fred = People.find(:name => 'fred')
>
> and an eye color database and you'd want all of the eye colors:
>
> @eye_colors = EyeColor.all
>
> and a Clothes table:
>
> @clothes = Clothes.all
>
> then all three variables with all the information you need is available for the view. The above would of course be done in a method in the controller.
>
> Am I missing something here?

Hmm. I'm not sure.

Well, for one thing, if EyeColor is a Sequel::Model (in which case, it would have to be Eyecolor), then "Eyecolor.all" will get the contents of the table, probably as an array of hashes. So if somebody adds a new eye color to the database, nobody's going to see that until Ramaze is restarted. That's why I mentioned 'live data' earlier.

But let's assume
@eye_color = Eyecolor

Now if we do something like "@eye_color.each {|color| blahblah}" we'll get live data from the database.

Let's see. What happens next?

myView.stuff_you_need_to_know_to_make_a_form(@eye_colors)
myView.add_form_for(@fred)

Actually, it would have to be more like
myVew.add_exclusive_list(@eye_colors)
myVew.add_nonexclusive_list(@clothing)


Hmmm.

One thing to keep in mind is that to make this example correspond more accurately to my data, we have to add Doll and Puppy objects, which also have .eyecolor and .clothing properties. Recoding for editing eye color on multiple pages isn't very DRY.

So I *could* have a partial template for eye color that was something like
<select name="eyecolor">
@eye_color.each do |ec|
<option value="ec.id" if @currentObject.eyecolor == ec then "selected" end >ec.color</option>
end
</select>

[Obviously, I have mixed Ruby and HTML willy-nilly here, in a way that would never work with a real templating engine, but hopefully you get the idea.]

Then my main template would look something like

<form method="post" action="enter">
<input type='hidden' name='id' value='@currentObject.id'>
<input type=text name="name" value='@currentObject.name'>
#include eyecolor-form
#include clothing-form
</form>

Hmm. Interesting.

Scott LaBounty

unread,
Sep 2, 2010, 8:46:44 PM9/2/10
to ram...@googlegroups.com
If someone adds a new eye color to the table, the next time you hit a controller method that requests it, you should pick it up and display it (unless I'm missing something here).

Scott



--
You received this message because you are subscribed to the Google Groups "Ramaze" group.
To post to this group, send email to ram...@googlegroups.com.
To unsubscribe from this group, send email to ramaze+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ramaze?hl=en.




--
Scott
http://steamcode.blogspot.com/

Dave Howell

unread,
Sep 2, 2010, 9:46:39 PM9/2/10
to ram...@googlegroups.com

On Sep 2, 2010, at 17:46 , Scott LaBounty wrote:

> If someone adds a new eye color to the table, the next time you hit a controller method that requests it, you should pick it up and display it (unless I'm missing something here).

Yes, but that happens ONLY if @eye_color = Eyecolor, NOT if @eye_color=Eyecolor.all, unless I include that not in an initiialization routine, but in the main body. That seems verbose and inefficient to me.


Lars Olsson

unread,
Sep 3, 2010, 4:34:58 AM9/3/10
to Ramaze
Warning: Sequel voodoo ahead! Ramaze will only be a bysander in this
post.

Ok, I've put together some examples showing how you can manipulate a
Sequel::Model object to show how you can get *exactly* the data you
want from it. Some comments on the code will appear below the
examples. Here we go:

--- Start example
# Load sqlite3-ruby
require 'sqlite3'

# Create a simple sqlite database that contains a single table. Add
some values to the table
SQLite3::Database.new('bodyparts.db') do |db|
db.execute("CREATE TABLE IF NOT EXISTS eyes (id INTEGER PRIMARY KEY
ASC, color TEXT, description TEXT)")
if db.get_first_value('SELECT COUNT(id) FROM eyes').to_i == 0
db.execute("INSERT INTO eyes (color, description) VALUES ('blue',
'Blue eyes')")
db.execute("INSERT INTO eyes (color, description) VALUES ('brown',
'Brown eyes')")
db.execute("INSERT INTO eyes (color, description) VALUES ('green',
'Green eyes')")
end
end

# Load Sequel
require 'sequel'

# Let sequel do sneaky stuff to connect to database
DB = Sequel.sqlite('bodyparts.db')

# Create a model that maps to the previously created table
class Eyes < Sequel::Model; end

# Try getting some data out
all_eyes = Eyes.dataset

# Print query
puts all_eyes.sql

# Print results
all_eyes.each do |ec|
puts "#{ec.id}\t#{ec.color}\t#{ec.description}"
end

# If we're only interested in eye colors, we don't need to fetch the
id or the description
eye_colors = Eyes.select(:color)

# You can verify that you eye_colors only contains eye colors by
checking the dataset
puts eye_colors.sql # returns SELECT `color` FROM `eyes`

# Print results
eye_colors.each do |ec|
puts ec.color
end

# If you want both color and description (but not id), just add the
columns you like to the select method
eye_colors_and_desc = Eyes.select(:color, :description)

# Print query
puts eye_colors_and_desc.sql

# ...and the results
eye_colors_and_desc.each do |ec|
puts "#{ec.color}\t#{ec.description}"
end

# Sequel models are essentially glorified Sequel datasets, which means
you can do filtering, sorting and other fun stuff directly on the
model.
eye_colors_starting_with_b = Eyes.select(:color).filter(:color.like('b
%'))

# print query
puts eye_colors_starting_with_b.sql

# ...and results
eye_colors_starting_with_b.each do |ec|
puts ec.color
end
--- End example

As shown above, Sequel models are actually very flexible. If you don't
want some partical piece of data in your model, its easy to exclude it
by using the Dataset.select method. All that Sequel::Model object
basically do is act as "proxy objects" for Sequel::Datasets. You can
of course add your own methods to a Sequel::Model, making it even more
flexible, but please keep in mind that a Sequel::Model can do
*everything* that a Sequel::Dataset can do. Filtering, Sorting,
aggregate functions, you name it. And since Datasets are "lazy", ie
don't run queries until the results actually are needed it does not
run "unneccessary" queries either. You can manipulate the dataset of
the model how you want whenever you want, nothing happens until you
actually try to *use* the data.

Normally, web applications using Sequel objects will query thing
"live". There *might* be some reason this doesn't work in your
particular case, but without seeing the actual app it hard to know.
There might be a caching problem or you might have told Sequel to act
differently (using eager loading comes to mind). I really can't say.
But "normal" behavior for Ramaze/Sequel is to pull live data.

/lasso

Scott LaBounty

unread,
Sep 3, 2010, 12:07:39 PM9/3/10
to ram...@googlegroups.com
OK, I thought he wanted something a bit different, so I wrote this code. Between the two of us, there must be something that he can use ;-).

This program shows a) how to grab an array from a dataset, b) use it in a controller method, c) pass it to the view, and d) shows that if something is added to the table, it will get displayed the next time we get the dataset. "Colors" here, are really just strings. Also, there's no "view" created, we just use the Ramaze default view.

<<
require 'rubygems'
require 'ramaze'
require 'sequel'

# Open the sqlite database colors.db if it exists
# or create it if it doesn't
DB = Sequel.sqlite("mvcpurity.sqlite")

# Don't add the table if it already exists.
if !DB.table_exists? :colors
    DB.create_table :colors do # Create a new table       
        primary_key :id       
        column :color, :text, :unique=>true       
    end
end

# Create a Color model.class
class Color < Sequel::Model; end

# Add a color using our model. Note the id tag should get filed in
# automatically.
Color.create(:color => 'a')

class MainController < Ramaze::Controller

    # Main method. Get the current list of colors and store them
    # in an array. Add a new color (which won't be displayed on this
    # page. Return a string (used by the view) with the name of the
    # page, list of the current colors, and a link to the other page.
    def index
        @colors = Color.select(:color).all
        add @colors.last.color
        %{
            "Index page" <br/>
            #{@colors} <br/>
            <a href="#{rs(:page1)}">Page 1</a>
        }
    end

    # Page 1 method. Get the current list of colors and store them
    # in an array. Add a new color (which won't be displayed on this
    # page. Return a string (used by the view) with the name of the
    # page, list of the current colors, and a link to the other page.
    def page1
        @colors = Color.select(:color).all
        add @colors.last.color
        %{
            "Page 1" <br/>
            #{@colors} <br/>
            <a href="#{rs(:index)}">Index</a>
        }
    end

    private

    # Add a new "color" which should get displayed the next time
    # a page is viewed. We're simply going to take the successor
    # to the string passed in, "last" and create a new Color from
    # it.
    def add(last)
        last.succ
        c = Color.create(:color => last.succ)
        c.save
    end
end

Ramaze.start

>>

Hopefully, there's something in here you can use or helps your understanding.

--
Scott
http://steamcode.blogspot.com/

Dave Howell

unread,
Sep 3, 2010, 9:30:40 PM9/3/10
to ram...@googlegroups.com

On Sep 3, 2010, at 1:34 , Lars Olsson wrote:

> Warning: Sequel voodoo ahead! Ramaze will only be a bysander in this
> post.
>

Wow. Thank you, Lars and Scott, for taking the time to do some coding for this.

It looks as thought I still might not be communicating very well, though.

[Lars's code for initializing table 'eyes' deleted for brevity]


> # Create a model that maps to the previously created table
> class Eyes < Sequel::Model; end
>
> # Try getting some data out
> all_eyes = Eyes.dataset

Interesting. I would have just done
all_eyes = Eyes

The following code works the same in either case:

> # Print results
> all_eyes.each do |ec|
> puts "#{ec.id}\t#{ec.color}\t#{ec.description}"
> end

> As shown above, Sequel models are actually very flexible.

Oh, yes, I know. I've already extended mine to provide better support for the UUIDs that I use as primary keys, and rudimentary support for Postgres's 'array' data type.

Now...

SQLite3::Database.new('bodyparts.db') do |db|

db.execute("CREATE TABLE IF NOT EXISTS people (
id INTEGER PRIMARY KEY ASC,
name TEXT,
eyecolor INTEGER)")

I'm not sure how to create a foreign key relationship from within Ruby/Sequel, and IIRC, SQLite doesn't support them anyway, but we don't need it defined on the database for this example.

class Person < Sequel::Model;
:many_to_one :eyes
end

newguy = Person.new
newguy.name = "Fred"
newguy.eyecolor = Eyes(:color => "blue")
newguy.save


Now, it's time to get serious, and jump over to Scott's code. I will assume there is a template for "index" that iterates through an instance variable called @everybody, and lets you click on one to display the details. This links to "website/details?id=", so we can find out more about them.

class MainController < Ramaze::Controller
def index
if not @everybody then
@everybody = Person.dataset
end
end

def details
@somebody = Person[request['id']]
end

def changedetails
@somebody = Person[request['id']]
end

def savechanges
# code for transferring the POSTed form back into the appropriate object
end
end

The template for "changedetails" presumably includes some code that is the functional equivalent of
<form method="post" action="savechanges">
<input type='hidden' name='id' value='@somebody.id'>
<input type=text name="name" value='@ somebody.name'>
*********
</form>

Those asterisks? That's where the code for choosing an eyecolor goes. It would look something like this:


<select name="eyecolor">
@eye_color.each do |ec|
<option value="ec.id" if @currentObject.eyecolor == ec then "selected" end >ec.color</option>
end
</select>

And when I write the code for the part of the site that handles dolls, and make some more templates, then I get to code that part *again.*

And when I do puppies? I get to code it *again.*

"Code it again" is, IMHO, the wrong answer.


But wait, there's more. This example is still too simple. Some of the objects I'm working with have another layer of associations in them. So, let's model another layer...


class Mall < Sequel::Model
many_to_many :people
many_to_many :dolls
end

class Family < Sequel::Model
many_to_many :people
many_to_many :puppies
many_to_many :dolls
end

(Yes, this is completely reasonable. The company receives shipments of material from a supplier. Each shipment has multiple expenses (people) associated with it, and each expense belongs to a particular category (eye color).)


class FamilyController < Ramaze::Controller
def index
if not @families then
@ families = Family.dataset
end
# et cetera
end

def details
@family = Family[request['id']]
end

def changedetails
@family = Family[request['id']]
end
end

Now my /family/details template has to look something like

<form method="post" action="savechanges">
<input type='hidden' name='id' value='@family.id'>
<input type=text name="surname" value='@family.surname'>
@family.members.each do |person|
<input type=text name="#{person.id}-name" value='person.name'>
*********
end
@family.puppies.each do |puppy|
<input type=text name="#{puppy.id}-name" value='puppy.name'>
*********
end
@family.dolls.each do |person|
<input type=text name="#{doll.id}-name" value='doll.name'>
*********
end
</form>


So that original five lines of code for selecting an eye color is now appearing eight times in five different templates.

And what happens if I change the model? Maybe it turns out that I need to add prescription information for people eyes, so they have to become ".lefteye" and ".righteye" I now have a lot of templates to change.

To me, this seems ridiculous.

Instead, my code has moved to something much more like

<form method="post" action="savechanges">
@family.to_form
</form>

So a Family object knows how to do do fields for its own columns, and it asks associated models to provide THEIR form-ready fields, which it modifies if necessary to support multiple instances of a model in the same form. Those models, in turn, can call THEIR associated models, and so on.

If I make a change to the database schema and add a field to something, I often don't have to make any changes to my Sequel Models, because Sequel's very smart about building a model from the database schema. Likewise, with the code I have now, I often don't have to make any changes to any OTHER parts of my code, because the forms are constructed programmatically within the models.


Lars Olsson

unread,
Sep 4, 2010, 3:50:23 AM9/4/10
to Ramaze
@Dave

I'll try to dive into your code example later, but for now I just
wanted to explain this tiny bit:

I said:
> # Try getting some data out
> all_eyes = Eyes.dataset

You said:
Interesting. I would have just done
all_eyes = Eyes

The reason for using Model.dataset was that I wanted to be able to do
this on the next line:
puts all_eyes.sql

If you try this:
Eyes.sql

it will fail with a NoMethodError, because the Eyes does not have the
sql method. The sql method belongs to Sequel::Dataset. I just wanted
to treat all variables the same.

Eyes # Returns the Eyes class
Eyes.dataset # Returns a Sequel::Dataset
Eyes.select(:color) # Returns a Sequel::Dataset
Eyes.filter(:color.like('b%')) # Returns a Sequel::Dataset

Almost every method call on a Sequel::Model returns a Sequel::Dataset.
'Eyes' by itself is just the Eyes class.

/lasso

Lars Olsson

unread,
Sep 4, 2010, 12:35:35 PM9/4/10
to Ramaze
Hi,

> I'm not sure how to create a foreign key relationship from within Ruby/Sequel, and IIRC, SQLite doesn't support them anyway, but we don't need it defined on the database for this example.
>
> class Person < Sequel::Model;
> :many_to_one :eyes
> end
>
> newguy = Person.new
> newguy.name = "Fred"
> newguy.eyecolor = Eyes(:color => "blue")
> newguy.save

SQlite supports foreign key relationships. You can use Sequel's
associate method to create a relationship between two tables
(regardless of which database your using.

--- Start example code
require 'sequel'

# Remove old database file
File.delete('bodyparts.db') if File.exists?('bodyparts.db')

BODYPARTS_DB = Sequel.sqlite('bodyparts.db')

# Needed for automatically creating tables. Not needed when the tables
are already created
Sequel::Model.plugin(:schema)

# The set_schema method is used to define the tables using Sequel.
This is for simplification only.
# In the real world you probably have pre-made tables and then you
only need to do
# class Person < Sequel::Model; end
class Person < Sequel::Model
self.db = BODYPARTS_DB
self.set_schema do
primary_key :oid
text :name
integer :eyes
end
self.create_table unless self.table_exists?
end

# Same as above, only different model
class Eyes < Sequel::Model
self.db = BODYPARTS_DB
self.set_schema do
primary_key :oid
text :color
text :description
end
self.create_table unless self.table_exists?
end

# Associate Person.eyes to Eyes.oid
Person.associate :many_to_one, :eyes, :class => Eyes, :key => :oid

# Create some eyes
Eyes.new(:color => 'blue', :description => 'Blue eyes').save
Eyes.new(:color => 'brown', :description => 'Brown eyes').save
Eyes.new(:color => 'green', :description => 'Green eyes').save

# Create Fred, a gentleman with blue eyes
blue_eyes = Eyes.filter(:color => 'blue').first # Returns a Eyes
object
fred = Person.new(:name => 'Fred', :eyes => blue_eyes)
fred.save

puts fred.name # Prints "Fred"
puts fred.eyes.color # Prints "blue"
--- End example code

And then on to your controller/views. The first part (ie, the actions)
looks beautifully clean and concise and captures the model in simple
instance variables. That is no problem. But then you're saying that
the *same* form will appear in several templates and it would lead to
code duplication if the *data* cannot render itself as HTML. That is
wrong in my opinion. The solution for displaying the same data on
different pages should really be solved in the view (the main subject
of the entire thread, methinks). So, how do we solve this in practice?

I would solve this particular problem like this.

1) Create *one* template that expects @data1, @data2 and so on
(capturing your model). This template will render your form
2) Use render_partial (or render file) to include the first template
in other templates.

Your model stays unaffected. Your first template might need to change
if the model changes, but only need to change it in one place (a
problem you can't escape even if your letting the model do the
rendering). All other templates stay unaffected. The only thing you're
changing is the "view", ie a template.

/lasso

Scott LaBounty

unread,
Sep 4, 2010, 1:00:38 PM9/4/10
to ram...@googlegroups.com
I'd just started looking at this too and I agree, render_partial is probably your answer (assuming you're not completely devoted to the way you're doing it now). Here's a link I found, but haven't had time to really look at, that may be helpful ...

http://blog.xambr.com/2009/11/26/ramaze-partials-with-etanni/

Scott

--
You received this message because you are subscribed to the Google Groups "Ramaze" group.
To post to this group, send email to ram...@googlegroups.com.
To unsubscribe from this group, send email to ramaze+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/ramaze?hl=en.




--
Scott
http://steamcode.blogspot.com/

Scott LaBounty

unread,
Sep 4, 2010, 4:57:40 PM9/4/10
to ram...@googlegroups.com
OK, here's a link to GitHub where I've put a simple Ramaze example (created with "ramaze create RenderPartial) using a technique that I think would work for you Dave ...

http://github.com/slabounty/RenderPartial

Here's the controller,

<<
class MainController < Controller
  # the index action is called automatically when no other action is specified
  def index
    @title = "Welcome to Ramaze!"
  end

  def page_1
    @title = "Page 1"
    @colors = ["blue", "brown", "hazel"]
  end

  def page_2
    @title = "Page 2"
    @colors = ["blue", "brown", "hazel"]
  end

end

>>

Obviously here you'd use Sequel models to generate the colors, but I wanted to keep this as simple as possible.

Here's the view/page_1.xhtml (and for all intents and purposes, view/page_2.xhtml which is mostly identical) ...

<<
<p>
    Page 1
    #{ render_partial :color }
</p>
>>

finally, the partial, view/color.xhtml

<<

<ul>
    <?r @colors.each do | color | ?>
        <li> #{color} </li>
    <?r end ?>
</ul>

>>

I think that *should* help DRY up your views. Is that what you were looking for? If not, that's OK, because I sure learned quite a bit from this exercise and I'll be posting this later on my blog.

Scott
--
Scott
http://steamcode.blogspot.com/

Scott LaBounty

unread,
Sep 4, 2010, 11:31:15 PM9/4/10
to ram...@googlegroups.com
A quick blog post on this one ... http://steamcode.blogspot.com/2010/09/ramaze-and-partial-rendering.html

Corrections, as always, are welcome and encouraged.

Scott
--
Scott
http://steamcode.blogspot.com/

ChrisB

unread,
Oct 5, 2010, 12:16:23 PM10/5/10
to Ramaze
I've been wrestling with the MVC issue and how it applies to Ramaze as
well (not in a bad way - I really like Ramaze).

Just to throw something in with respect to your ideas on views. Having
used ERB and then HAML I've gravitated towards using Erector for my
views (http://erector.rubyforge.org/). With Erector views are full
blown classes in their own right - you pass the data into the view as
named parameters. This approach means that you don't automatically get
access to the instance variables in the controller but you do get a
clean decoupling between the controller and the view as per a strict
interpretation of the MVC pattern. One advantage of this approach is
that you can easily write unit tests for your views - invocation of
the view is not dependant on having the controller available.

Rather than have the controller implicitly call the view I explicitly
call the view as follows, passing in the required data:

MyView.new(:mydata => MyModel.find(:id=>1)).to_s

The to_s method simply streams the output as html. If there is no
associated view template Ramaze outputs the html.

Erector also provides an alternative take on layouts. As views are
classes you can implement your layout as a superclass and use
inheritance to specialize your individual views by overriding some of
the methods (e.g. the content area). As a result of this I don't use
the Ramaze layouts option.

You can also implement individual view components (e,g, menu bars,
tables, forms etc) as widgets and call them from your layout classes
and view sub-classes. I've found this a much nicer way of modularizing
your view code than using partials.

I've started to experiment with the provides statement to allow
alternative outputs from the same controller method (jason, yaml,
xml). I think my use of Erector might result in a consistent appropach
- the controller gets the required set of data and the provide
statement passes the data into a specialized view for the required
output (cf the Erector call).

There is an Erector view engine option in Ramaze but I think this is
based on using the Erector inline coding approach - i.e. it treats
Erector as it would any other templating engine. I think the approach
I'm using is more attune with the Erector philosophy at the expense of
going against the "standard" Ramaze approach to MVC.

I'm not saying this is the right or best way of going about things but
at the moment I'm happy with the results. I'd really appreciate
comments on this approach and it's "legitimacy" with respect to the
Ramaze way of doing things.

ChrisB

unread,
Oct 5, 2010, 12:14:30 PM10/5/10
to Ramaze
I've been wrestling with the MVC issue and how it applies to Ramaze as
well (not in a bad way - I really like Ramaze).

Just to throw something in with respect to the discussion on views.

Dave Howell

unread,
Feb 8, 2011, 5:30:55 AM2/8/11
to ram...@googlegroups.com
OK, I give up. I missed the meeting or lost the memo or something, but I think I've spent at least fifteen hours now trying to figure out how to get the site to stay up and running without me holding its hand, and I cannot for the life of me figure out what's going on.

Lots of places happily tell me I can just enter "$ramaze start". Yes, of course. From a command line I have opened, and after "cd /my/site/root/directory". But "deployment" means NOT typing stuff at the command line. It has to be launched as a cron job, or by some task-launching daemon, not by me. I have not found any clue how to do "ramaze start-from-that-directory-over-there-not-the-one-we're-in-now."

Which would help with the problem that Ramaze needs to get itself up in the morning and get to work without me having to start it by hand. THAT is the absolutely essential part that I cannot find anybody even mentioning in passing, never mind actually providing an example of some kind to show how it could be done.

The wiki says that 'Mongrel is the recommended way of deploying a Ramaze app.' OK, sure. And that means . . . something so obvious it goes without saying, I guess. {sigh} There's an Apache reverse-proxy configuration. Nice, but I have that part working just fine. I need the part BEFORE that.

Or, maybe my production server is brain-damaged, and one of the things I've already tried *should* have worked. I don't like the fact that "ramaze" isn't in my path for no obvious reason.
$cd /my/laptop/test/directory
$ramaze start
works fine . . . on my laptop. But on my Ubuntu server, I have to provide a full path to Ramaze.

Well, fine, whatever, I can do that. In fact, if I type it in from a command line, everything works just fine . . . until I tear down the ssh pipe to the server. That tears down the Mongrel/Ramaze task as well, and poof! the site is gone. Well, that's not exactly unexpected, after all. That's why I use watchdog or launchd or cron on my XServe for tasks that need to stay up and running. Ubuntu doesn't have launchd or watchdog. It does have cron. Cron is willing, under extremely specific circumstances, to launch ramaze, for about 80 milliseconds. Cron is killing the tasks the instant they finish launching. Or maybe they're just dying the instant they finish launching.

I have no idea.

So if anybody feels up to telling me what (hopefully) incredibly obvious simple thing I'm supposed to know about this, I would be most appreciative.

Nick Robinson-Wall

unread,
Feb 8, 2011, 6:27:22 AM2/8/11
to ram...@googlegroups.com
Hi Dave,

A few options for you:
1) (My personal choice) The passenger apache mod: http://www.modrails.com/ - point a vhost at your public/ dir and it'll do the rest. You need to set up persistent caching etc in your start.ru file if this is necessary for your application.

2) GNU screen: http://www.gnu.org/software/screen/ - run your ramaze start command inside a screen session and detach.

3) Prevent your terminal hangup from killing ramaze: nohup ramaze start &

With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem. When first deploying ramaze applications on debian systems I gave up on debianised-ruby, compiled ruby myself and suddenly all my problems disappeared. For reference, my ramaze binary is in /usr/local/lib/ruby/gems/1.9.1/gems/ramaze-2010.06.18/bin, but there is also a copy of this in /usr/local/bin.

In any case I personally prefer just to ./start.rb or ruby start.rb when testing applications, I do all live deployment through passenger.

Regards,
Nick

Yorick Peterse

unread,
Feb 8, 2011, 7:46:23 AM2/8/11
to ram...@googlegroups.com
Dave,

Don't get me wrong but your attitude feels somewhat negative based on the way your Email is written. Ramaze can be deployed using many different forms such as Capistrano, Vlad or Git (my personal favorite). When it comes to webservers
it really depends on how you deploy it. When deploying via Git you can use hooks and tell Git to restart your webserver after each commit. If you want to start an application at certain intervals it's best to use cronjobs or Whenever.

What I use for deployment is Git (like mentioned before). Using a post-receive hook you can then update the remote repository (on the live server) and execute any number of different tasks (hooks are just shell scripts). The basic workflow is pretty simple, you stage and commit your changes to your public/private repository and verify them. Once they're good to go you'd do something like git push live master, wait a few seconds and you're pretty much done.

Yorick

Kevin Smith

unread,
Feb 8, 2011, 10:18:02 AM2/8/11
to ram...@googlegroups.com
Hopefully I am understanding your issue. This does seem to be a blind
spot with developers of web frameworks, not just ramaze.

I experienced almost exactly the same frustration a couple years ago. I
also spent hours trying to figure out how to get my ramaze site working
as a daemon in production, after getting it working on an interactive
command line. I posted some questions but nobody really seemed to
understand what I was asking. I finally figured it out, and I'm sorry I
didn't find the time and place to share what I learned. Here is my
attempt to rectify that.

Part of the problem is that there are a lot of different ways to do it,
depending on what infrastructure you choose. It is much easier if you
use apache, which I don't because I find it to be huge and complex.

On my ubuntu server, I need to host multiple domains, so I chose pound
to handle that part. I won't discuss that here. Some of my sites are
static, so I use nginx for those. For my dynamic (ramaze) site(s) nginx
delegates to thin. If your only site is a ramaze site, you can probably
skip pound and nginx and just go straight to thin.

My thin yml file for my ramaze site looks like this:
---
pid: /tmp/pids/thin-example.com.pid
log: /var/log/thin-example.com.log
max_conns: 1024
timeout: 30
#port: 8100 # port not used--overridden by start.rb
chdir: /var/www/example.com
environment: development
max_persistent_conns: 512
#address: 127.0.0.1 # address not used--overridden by start.rb
#daemonize: true # daemonize probably ignored by thin
require: []

After setting that up, I tested by running thin on the command line, and
saw that it launched ramaze properly. Once that was working, I used
thin's daemon mode by saying something like:
sudo /etc/init.d/thin start

Presto magico, the site will now start in the background (persisting
after you terminate your ssh session), and it will automatically restart
whenever the server is restarted.

I hope that helps, and if so, perhaps you can carry this forward and
submit some patches to get it included in the ramaze documentation.

Kevin

Dave Howell

unread,
Feb 8, 2011, 4:09:13 PM2/8/11
to ram...@googlegroups.com

On Feb 8, 2011, at 4:46 , Yorick Peterse wrote:

> Dave,
>
> Don't get me wrong but your attitude feels somewhat negative based on the way your Email is written.

Well, I don't *think* I'm 'getting you wrong,' and oh, yes, I'm sure it does. What I really *wanted* to write involved lots and lots of bad language and disparaging comments about Unix's parentage. However, that would have been much less likely to get me any helpful responses at all. {chuckle} I tried to not spew buckets of bile, but I'm not surprised if a bit of it leaked through.

> Ramaze can be deployed using many different forms such as Capistrano, Vlad or Git (my personal favorite). When it comes to webservers it really depends on how you deploy it.

Well, yes, and Li/U-nix offers ever so many alternatives, I'm sure. I was just rather piqued that I was unable to find even a single actual example of somebody doing so . . .

> What I use for deployment is Git (like mentioned before).

Ah. I certainly have friends to adore Git. At the moment, I don't really have (at least as far as I can recognize) any other good uses for Git, so it would involve installing, integrating, and learning what appears to be a fairly large and potentially elaborate new tool. Since it's just one web site, and just one programmer, I'll probably see if I can get something simpler working first.

I wouldn't be surprised, though, if somebody else Googled up this thread at a later date and said "Oh, hey! Yea, Git would do it, and we're already running that!" {smile}

Dave Howell

unread,
Feb 8, 2011, 4:26:33 PM2/8/11
to ram...@googlegroups.com

On Feb 8, 2011, at 3:27 , Nick Robinson-Wall wrote:

> Hi Dave,
>
> A few options for you:
> 1) (My personal choice) The passenger apache mod: http://www.modrails.com/ - point a vhost at your public/ dir and it'll do the rest. You need to set up persistent caching etc in your start.ru file if this is necessary for your application.

I believe that this would assume that I was actually running Apache on my Ubuntu box, then? In my particular instance, Apache is running on my XServe, which handles most of my web sites, but it is reverse-proxying this particular bit over to the Ubuntu box, which isn't (at least so far).

> 2) GNU screen: http://www.gnu.org/software/screen/ - run your ramaze start command inside a screen session and detach.

Based mostly on the name of this, I'm guessing that wouldn't help with having the Ramaze site auto-launch on a reboot, though?

> 3) Prevent your terminal hangup from killing ramaze: nohup ramaze start &

Hmm! I'd been trying the & with cron to try to make it let go of Ramaze so it could keep running, but I've never heard of 'nohup' before.

> With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem.

Wouldn't surprise me. I *was* a bit surprised that "gem install ramaze" still didn't get Ramaze into my path, but only a bit.

Dave Howell

unread,
Feb 8, 2011, 6:01:37 PM2/8/11
to ram...@googlegroups.com

On Feb 8, 2011, at 3:27 , Nick Robinson-Wall wrote:

> With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem.

Although I'm not sure yet, it looks like this will be the key clue to fix the problem.

I know there's kind of a religious war about whether gems should be installed with gem or with the Debian package tools (apt-get or aptitude). I've also found that, for all of aptitude's attitude about how you should never try to end-run around the Debian package manager, upon closer inspection, it became clear that it had *completely* botched the installation of gems.

$irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'ramaze'
LoadError: no such file to load -- ramaze

Gimme a break.

So I downloaded rubygems myself, installed it, and asked it to start installing gems. I was not surprised to find that it was completely unaware of all the gems that had already been installed. Clearly, the Debian-installed RubyGems was being told to install everything where nobody would ever be able to find them. Nice.

I'll follow up this message if/when I've got something else to report.


Christian MICHON

unread,
Feb 8, 2011, 6:20:18 PM2/8/11
to ram...@googlegroups.com
On Wed, Feb 9, 2011 at 12:01 AM, Dave Howell
<groups...@grandfenwick.net> wrote:
>
> On Feb 8, 2011, at 3:27 , Nick Robinson-Wall wrote:
>
>> With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem.
>
> Although I'm not sure yet, it looks like this will be the key clue to fix the problem.
>
> I know there's kind of a religious war about whether gems should be installed with gem or with the Debian package tools (apt-get or aptitude). I've also found that, for all of aptitude's attitude about how you should never try to end-run around the Debian package manager, upon closer inspection, it became clear that it had *completely* botched the installation of gems.
>
>        $irb
>        irb(main):001:0> require 'rubygems'
>        => true
>        irb(main):002:0> require 'ramaze'
>        LoadError: no such file to load -- ramaze
>
> Gimme a break.

try the following commands:

1/ gem env
already at this stage you should know if something is wrong with your
system... look out for gem paths

2/ gem list
obvious, once you've the above ok, to check out what is installed or
not (at least, you've a list)

>
> So I downloaded rubygems myself, installed it, and asked it to start installing gems. I was not surprised to find that it was completely unaware of all the gems that had already been installed. Clearly, the Debian-installed RubyGems was being told to install everything where nobody would ever be able to find them. Nice.
>
> I'll follow up this message if/when I've got something else to report.
>
>

side question to the rest of the list: can bundler work with ramaze
like it does with rails ? I googled for this but I could not find
it...

--
Christian

Dave Howell

unread,
Feb 8, 2011, 7:24:57 PM2/8/11
to ram...@googlegroups.com

On Feb 8, 2011, at 15:01 , Dave Howell wrote:

>
> On Feb 8, 2011, at 3:27 , Nick Robinson-Wall wrote:
>
>> With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem.
>
> Although I'm not sure yet, it looks like this will be the key clue to fix the problem.

And it was.

It's funny that nobody ever posted (that I could find) on the web that the simplest way to deploy Ramaze is just giving cron

cd /web/site/directory/here; ramaze start

to execute on system boot. Which is what I tried at the very beginning, but since I was unaware that the gems were completely flabligated from a non-login shell, I had no idea why it didn't work.

I am, actually, using a slightly fancier approach. Instead of "ramaze start" I'm using "ruby start.rb" and added some code to start so that it first checks to see if the site is already up, running, and responding normally, and calls Ramaze if it isn't. Then cron is instructed to re-execute my command every, oh, ten minutes at the moment. That way, if buggy code or some such causes the site to go down, it should restart within ten minutes.

Yea, I know, there are much fancier/better/more sophisticated ways to do this. ("Thin" I believe was suggested earlier in this thread.) And I promise I'll look into them soon. But this way requires nothing new to be installed.

Thanks, all.

Christian MICHON

unread,
Feb 9, 2011, 3:39:55 AM2/9/11
to ram...@googlegroups.com
On Wed, Feb 9, 2011 at 1:24 AM, Dave Howell
<groups...@grandfenwick.net> wrote:
>
> On Feb 8, 2011, at 15:01 , Dave Howell wrote:
>
>>
>> On Feb 8, 2011, at 3:27 , Nick Robinson-Wall wrote:
>>
>>> With regard to the ramaze command not being in your $PATH, I suspect this is an ubuntu/debian problem.
>>
>> Although I'm not sure yet, it looks like this will be the key clue to fix the problem.
>
> And it was.
>
> It's funny that nobody ever posted (that I could find) on the web that the simplest way to deploy Ramaze is just giving cron
>
>        cd /web/site/directory/here; ramaze start
>
> to execute on system boot. Which is what I tried at the very beginning, but since I was unaware that the gems were completely flabligated from a non-login shell, I had no idea why it didn't work.

did you ever type 'ramaze -h' ?

>
> I am, actually, using a slightly fancier approach. Instead of "ramaze start" I'm using "ruby start.rb" and added some code to start so that it first checks to see if the site is already up, running, and responding normally, and calls Ramaze if it isn't. Then cron is instructed to re-execute my command every, oh, ten minutes at the moment. That way, if buggy code or some such causes the site to go down, it should restart within ten minutes.
>

nothing wrong in using 'ruby start.rb' when you're developing the application.

> Yea, I know, there are much fancier/better/more sophisticated ways to do this. ("Thin" I believe was suggested earlier in this thread.) And I promise I'll look into them soon. But this way requires nothing new to be installed.

wrong. you need to install 'thin' gem and this requires OS specific
extensions (without a toolchain, you will not be able to install it).

you should get a more decent return on time investment in looking at
jruby + warbler + tomcat instead. Though I've not tried this yet with
ramaze, it was working fine with rails apps. No command line involved
once the war file is ready for deployment: you're doing this using
tomcat web interface.

My 2 cents

--
Christian

Yorick Peterse

unread,
Feb 9, 2011, 4:43:06 AM2/9/11
to ram...@googlegroups.com
Christian,

Bundler works fine with Ramaze. In fact, it works with every given application or framework. All you have to do is create a file called "Gemfile" with the following contents:

  source :rubygems
  gem 'ramaze'
  gem 'something_else'

From that point on you can just execute the command bundle install and you're good to go.

Yorick

Christian MICHON

unread,
Feb 9, 2011, 5:07:42 AM2/9/11
to ram...@googlegroups.com
On Wed, Feb 9, 2011 at 10:43 AM, Yorick Peterse <in...@yorickpeterse.com> wrote:
> Christian,
> Bundler works fine with Ramaze. In fact, it works with every given
> application or framework. All you have to do is create a file called
> "Gemfile" with the following contents:
>   source :rubygems
>   gem 'ramaze'
>   gem 'something_else'

I'm not 'this new' in the ruby area, so I already know this of course
and using it with rails. But thanks anyway :-)

What I truly meant was (and sorry again if I wasn't clear enough): how
to tweak ramaze internals so that bundler is called when gems are
missing ?

For rails 3, it's working out of the box. For rails 2.3, the following
instructions are needed: http://gembundler.com/rails23.html

I'm looking for similar instructions for ramaze...

--
Christian

Yorick Peterse

unread,
Feb 9, 2011, 7:15:23 AM2/9/11
to ram...@googlegroups.com
Christian,

How Rails and Padrino do it is by using the Bundler API. More about this can be found here: http://gembundler.com/bundler_setup.html

Yorick

Christian

zahna

unread,
Feb 10, 2011, 8:48:46 AM2/10/11
to Ramaze
Here is the very top of my app.rb (assuming you have an app.rb
generated by ramaze when you started your project):

# This file contains your application, it requires dependencies and
necessary
# parts of the application.
#
# It will be required from either `config.ru` or `start.rb`

require 'rubygems'
require 'bundler'

# Ensure we have the right gems, as listed in Gemfile
begin
Bundler.require(:default)
rescue
$stderr.print($!)
puts("\nAttempting to install required gems.")
puts(`bundle install`)
puts("`bundle install` complete. Please restart.")
exit(0)
end

require 'ramaze'

<blah_blah_rest_of_file>


So there's an example of integrating Bundler into Ramaze. For those
of you familiar with Bundler, let me know your opinion of this method,
or if there are better methods. Thanks!


On Feb 9, 5:07 am, Christian MICHON <christian.mic...@gmail.com>
wrote:

Dave Howell

unread,
Feb 10, 2011, 4:15:11 PM2/10/11
to ram...@googlegroups.com

On Feb 9, 2011, at 0:39 , Christian MICHON wrote:

> On Wed, Feb 9, 2011 at 1:24 AM, Dave Howell
> <groups...@grandfenwick.net> wrote:
>
>> Yea, I know, there are much fancier/better/more sophisticated ways to do this. ("Thin" I believe was suggested earlier in this thread.) And I promise I'll look into them soon. But this way requires nothing new to be installed.
>
> wrong. you need to install 'thin' gem and this requires OS specific
> extensions (without a toolchain, you will not be able to install it).

I wasn't clear. Using *cron* requires nothing new be installed. "Thin" of course would, which is why I didn't try using it right away.

> you should get a more decent return on time investment in looking at
> jruby + warbler + tomcat instead.

Hmm. OK, recommended choices include "thin" with my existing ruby, or those three. Excellent!

I'll have to look into those. Something's not copacetic with what I have. My script is leaving me a log trail; every ten minutes Cron fires it off, and it does a test of the site by using "curl" to retrieve a special diagnostic test page. Every 1-2 hours, the test fails, and my start script has to retrieve the PID, kill it, and restart Ramaze. I don't know how to get Ramaze to log errors, or maybe I do, but whatever's causing the fault isn't creating a log trail. Since the failures are occurring even at three in the morning, I don't think it's something that users are doing to the site; it's just . . . stopping.

Suggestions for finding useful diagnostic clues?

Michael Lang

unread,
Feb 11, 2011, 8:37:14 AM2/11/11
to ram...@googlegroups.com
Given your reverse-proxying and thus no need to front your app with
Apache/Passenger, I would highly recommend launching and maintaining
your ramaze app using either monit or god. Both are designed to do
exactly what you're starting to piece together scripts to do:

http://god.rubyforge.org/
http://mmonit.com/monit/

They can launch, monitor, ping, restart, watch memory consumption,
email you statuses and all that good stuff. Well worth the investment
to learn one or the other.

Michael

> --
> You received this message because you are subscribed to the Google Groups "Ramaze" group.
> To post to this group, send email to ram...@googlegroups.com.
> To unsubscribe from this group, send email to ramaze+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/ramaze?hl=en.
>
>

--
http://codeconnoisseur.org

James Britt

unread,
Feb 24, 2011, 9:46:05 AM2/24/11
to ram...@googlegroups.com
Christian MICHON wrote:
>
> you should get a more decent return on time investment in looking at
> jruby + warbler + tomcat instead. Though I've not tried this yet with
> ramaze, it was working fine with rails apps. No command line involved
> once the war file is ready for deployment: you're doing this using
> tomcat web interface.
>
> My 2 cents


I had a Ramaze app in production for about a year or so, using jruby +
warbler.

I had some trouble getting everything "just so", but once running it was
amazingly solid.

My issues were primarily related to Glassfish confguration (like Tomcat,
but lighter), and Warbler being written as if all Rack apps were Rails
apps.

However, nowadays I run Ramaze apps in one of two ways. The prefered
way is to use it with Apache + Passenger Phusion. "It Just Works (tm)!"
(Note: I'd look at nginx if I had more free time; Apache works OK for
me, but people speak highly of nginx, especially if you are not needing
any Apache-specific modules or features.)

Or, I ssh to the server, start a screen session, and run the app from
the commandline using WEBrick or Mongrel, and ctrl-D out of screen. I
do this for smallis stuff when I want a simple service for some perioid
of time. I don't think I'd want to run a site like that full-time.

OTOH, that's exactly how ruby-doc.org was running for quite a few years.
:) (However, it required regular checking and bouncing.)

If you go the phusion way, then Capistrano can help if you don't want to
be manually ssh'ing to the server or any of that stuff.


James

--

jamesbritt.com - Playing with Better Toys
neurogami.com - Smart application development
azhackers.com - Feed your head. Hack your world.

Reply all
Reply to author
Forward
0 new messages