July 10, 2014
On 09/07/14 21:37, Nick Sabalausky wrote:

> What I've started doing, and absolutely love so far, is to write my
> forms purely in the HTML template (with a little bit a custom
> tags/attributes), then use Adam's HTML DOM to read that HTML form and
> generate all the backend form-handing *from* the HTML form, including
> all the appropriate per-field "validation failed".
>
> I'm finding this works a lot better than defining forms in the backend
> code and then trying to generate the HTML I want from that.

To me that sounds a bit backwards. I'm not exactly sure what you mean by "backend form-handling" but in Rails all ActiveRecord classes can take a hash (associative array) in the constructor. The keys will match the fields (columns) on the class and the constructor will automatically assign all fields with the given values. This is called mass-assignment.

The view uses appropriate names for the form fields, scoped in the same name as the model, like this:

<input type="text" name="person[name]" />

So the only thing you need to do in the controller is something like this:

def create
  user = User.new(params[:user])
  user.save
end

In the view you use a form builder:

= simple_form_for @user do |f| do
  = f.input :name
  = f.input :admin
  = f.association :role
  = f.button :submit

Here I'm using a plugin called SimpleForm, it will automatically render the correct input form type based on the column type in the database. "name" will be render as a text input. "admin" will be render as a checkbox (since it's a boolean). It will also add labels and similar things. It can also generate all necessary code to be compatible with Bootstrap.

"f.association :role" is quite interesting. This expects there to be an association to the Role model in the User model. It will render a select tag populated with all the rows from the Role table.

The validation is handled in the model, where it belongs, when "save" is called in the controller. There's also a plugin that will automatically add JavaScript validations. It has duplicated the standard Rails validators in JavaScript. It will inspect the model, choose the correct validator and add it when rendering the view.

-- 
/Jacob Carlborg
July 10, 2014
On Wednesday, 9 July 2014 at 21:07:26 UTC, Johannes Pfau wrote:
> Am Wed, 09 Jul 2014 17:28:42 +0000
> schrieb "Dicebot" <public@dicebot.lv>:
>
>> On Wednesday, 9 July 2014 at 17:05:21 UTC, Johannes Pfau wrote:
>> > Completely off-topic, but:
>> >
>> > Have you considered making vibe http-backend independent?
>> > So that it could provide a fcgi interface or be included in an nginx
>> > plugin?
>> 
>> What is the benefit as opposed to using proxy_pass at nginx? fcgi will be slower than built-in vibe.d HTTP server.
>
> FCGI was only an example. I guess the only benefit is that the webserver
> can spawn fcgi backends when it starts and files with certain
> extensions can be handled with these backends.
>
> But that's of course only useful with shared libraries / pages.

vibe.d can do it internally by having different routes for different file types and doing dynamic load if desired. Being 100% independent of HTTP server frontend is a big feature in my opinion.
July 10, 2014
On Thursday, 10 July 2014 at 10:24:23 UTC, Dicebot wrote:
> On Wednesday, 9 July 2014 at 21:07:26 UTC, Johannes Pfau wrote:
>> Am Wed, 09 Jul 2014 17:28:42 +0000
>> schrieb "Dicebot" <public@dicebot.lv>:
>>
>>> On Wednesday, 9 July 2014 at 17:05:21 UTC, Johannes Pfau wrote:
>>> > Completely off-topic, but:
>>> >
>>> > Have you considered making vibe http-backend independent?
>>> > So that it could provide a fcgi interface or be included in an nginx
>>> > plugin?
>>> 
>>> What is the benefit as opposed to using proxy_pass at nginx? fcgi will be slower than built-in vibe.d HTTP server.
>>
>> FCGI was only an example. I guess the only benefit is that the webserver
>> can spawn fcgi backends when it starts and files with certain
>> extensions can be handled with these backends.
>>
>> But that's of course only useful with shared libraries / pages.
>
> vibe.d can do it internally by having different routes for different file types and doing dynamic load if desired. Being 100% independent of HTTP server frontend is a big feature in my opinion.

Yes, that's what I use. I have this in my vibe.d code (to solve the problem that Chrome/Chromium play sound files only once):

router.get("*.wav", &handleAudioRequest);

private void handleAudioRequest(HTTPServerRequest req, HTTPServerResponse res) {
  res.headers.addField("Accept-Ranges", "bytes");
}
July 10, 2014
On Thursday, 10 July 2014 at 07:56:43 UTC, Jacob Carlborg wrote:
> To me that sounds a bit backwards.

I can go both ways, depending on the design of the form and how many helper tags we decide to use for the project.

My dom library doesn't dictate how you do it, of course, it just provides access to the html structure and has functions to help build one. But among the functions I've written for this are:

createAutomaticForm, which is found in my web.d module. It takes a D function signature and creates a form to call it, using static type info to generate the appropriate inputs.

This is a really old demo but still shows the principles:

http://arsdnet.net/cgi-bin/apidemo/add-some-numbers

That form is generated from "int addSomeNumbers(int a, int b);" The URL routing, field names, and types are pulled out of the identifiers used in D.

http://arsdnet.net/cgi-bin/apidemo/get-a-box

This one is "Element getABox(Color color);" with "enum Color { list here... }". Enums are rendered as <select>.



I find this is really convenient to quickly throw something up (web.d will do it automatically for any exported function that doesn't have a custom form function), but real web designs tend to need more flexibility so it doesn't do everything.


I have three other solutions too:

1) Just write the HTML form manually and fill it in with dom helper functions. This has become my preference in a lot of cases, it is really easy.

<form id="foo">
  <input type="text" name="field" />
  <textarea name="other"></textarea>
  <select name="auto_list" data-options-from="some_backend_item"></select>
  <select name="list">
     <option value="whatever">Cool</option>
  </select>
</form>

And so on and so forth. A lot of people don't like html, but I don't mind it at all; especially once you start using html5 attributes, it is fairly concise for this stuff.

Another thing I like with this is the designer can write it with just a plain browser, no need for the whole backend infrastructure just to see some quick tweaks. Helps a lot when they are working offline too.

Filling data is easy. Either use the functions directly:

auto form = document.requireSelector!Form("#foo");

foreach(k, v; your_data)
   form.setValue(k, v);


Or, if you are using my database.d with dom.d, relatively recent versions include a fillForm function:

fillForm(form, your_object, "object_name"); // object_name is used if the function takes a struct rather than individual items - another relatively new feature


To fill in data from a form, you can most easily use my DataObject class from database.d which doesn't take a hash constructor like Ruby but with foreach, it is close enough:

auto obj = new DataObject(db, "table"); // you could subclass it for a specific table, database.d even has functions to generate those classes from MySQL CREATE TABLE declarations automatically

foreach(k, v; cgi.post)
   obj[k] = v;

or you could easily enough list the expected keys in that filling loop, kinda like the Rails strong params (as I understand them - rails is now my day job but I'm still a bit of a n00b).



Filling the form data and generating the model updates was the most painful part of writing PHP IMO, so dom.d made them all stupid simple. Now I don't feel the need for form helpers, the DOM is smart enough to fill in the gaps from whatever it is given.

dom.d also has a function to get a value hash out of a form but I never actually used it. Maybe with local imports, I can make that smarter and selectively depend on cgi.d to actually have it cool. I gotta come back to this stuff some day.


2) Generate the HTML with the DOM library along with helper D functions to ensure more consistency.

auto form = cast(Form) Element.make("form");

form.addField("name", "value", [options]);

addField has several overloads that pick the right HTML to make from a given data type. It generates consistent HTML for labels and spans so it is easy to style with CSS.

But since this is D, it is a bit harder to pass to a HTML guy to edit the design. Otherwise though, dom.d's helper functions make all kinds of manipulations really easy and it is tempting to use more than I probably should.


3) Some hybrid, where you use custom tags in the HTML which are run. dom.d's more recent versions also include passing <%= %> and similar tags to a handler, if we really wanted to, we could use scripts there as well as custom tags and data attributes to fill things in.

Early on, I used a LOT of custom tags, but nowadays I prefer to stick to mostly standard HTML so it works better stand alone.

> The view uses appropriate names for the form fields, scoped in the same name as the model, like this:

Yeah, that's pretty nice. database.d's fillData (on which dom.d's fillForm is based and web.d does the same for struct arguments) just uses dots:

name="person.name"

which would fill the

void handler(Person person);

person.name field there. Then you do person.toDatabaseObject (an auto-generated function btw) to get a SQL builder class out of it and modify it if you want then finally just person.commitChanges(); which is like Rails' .save!

Perhaps I'll make the mixin just throw in a save method at some point too.



This stuff is fairly new and underdocumented/advertised, even my by lax standards. I think this is the first time I've even talked about it on the forums.


tbh from what I've seen, my collection of stuff is closer to the "full web framework" than vibe.d itself - as we discussed a couple months ago, I also have my SASS like css expander (which unlike the real sass doesn't need the rest of your life to recompile after any trivial change... though it is admittably still slow for D), javascript expanders and generators, various SQL backends, the list goes on.
July 10, 2014
On Wednesday, 9 July 2014 at 19:05:54 UTC, w0rp wrote:
> * An ORM, which absolutely must have a way to build queries a piece at a time without writing any SQL, like Django.

I'm skeptical of the benefit of full ORM, but my database.d goes to the point I believe is useful with two classes (and a few helper functions): DataObject, which allows easy inspection and setting of individual items and SelectBuilder which just builds a query.

> * A framework for generating all of the SQL required for database migrations like South or the built in migrations in Django 1.7, so you can quickly change any model.

I never did this automatically, I just wrote change files in sql myself before taking the RoR job... and personally I think Rails migrations aren't all that great, but it is nice that they are standardized; I can do the rails g migration here and the boss can shoot it up to heroku and it all usually just works.

> * An API for creating form handlers, especially for creating instances of models in the ORM through forms. (Django Form and ModelForm)

see my other email

> * An HTML template system which doesn't eat memory at compile time and where changes can be made while the development server is running.

I've thought about using dom.d at compile time, it now works there and could potentially do static checks on html well-formedness, broken links, correct field names, etc. But I never actually bothered, instead it just loads the file - convenient for tweaks by the rest of the team without recompiling anyway!

> * Django's automated testing framework lets you test pages with session data and email output, so I have tests for complex things like checkouts which are very easy to write.

I've done nothing like that. I kinda like this thing one of my rails coworkers pointed me toward there though called capybara. You fetch pages and tell it to click on buttons to do integration tests on html. It'd be almost trivial to do that with my cgi.d and dom.d - cgi.d already includes simulated requests (for command line testing, you run the binary like ./my_server GET /foo bar=baz and it runs the program with the given arguments) and dom.d can easily click/inspect the output.

But I haven't actually done it.

> * The Django pipeline module provides mechanisms for generating JS and CSS. I now have SCSS which regenerates CSS automatically during development

I've been using scss for the Rails job and I like that it has similar functionality to my own css expander (in html.d on my misc github, also now as a separate dub package called cssexpand), but I can't stand how BRUTALLY slow it is.

Some of the features it offers over cssexpand are kinda cool, but if the price is that high, it just isn't worth it. I'll stick to my simple nesting expansion and text macro replacement.
July 10, 2014
On Thursday, 10 July 2014 at 13:42:30 UTC, Adam D. Ruppe wrote:
> On Thursday, 10 July 2014 at 07:56:43 UTC, Jacob Carlborg wrote:
>> To me that sounds a bit backwards.
>
> I can go both ways, depending on the design of the form and how many helper tags we decide to use for the project.
>
> My dom library doesn't dictate how you do it, of course, it just provides access to the html structure and has functions to help build one. But among the functions I've written for this are:
>
> createAutomaticForm, which is found in my web.d module. It takes a D function signature and creates a form to call it, using static type info to generate the appropriate inputs.
>
> This is a really old demo but still shows the principles:
>
> http://arsdnet.net/cgi-bin/apidemo/add-some-numbers
>
> That form is generated from "int addSomeNumbers(int a, int b);" The URL routing, field names, and types are pulled out of the identifiers used in D.
>
> http://arsdnet.net/cgi-bin/apidemo/get-a-box
>
> This one is "Element getABox(Color color);" with "enum Color { list here... }". Enums are rendered as <select>.
>
>
>
> I find this is really convenient to quickly throw something up (web.d will do it automatically for any exported function that doesn't have a custom form function), but real web designs tend to need more flexibility so it doesn't do everything.
>
>
> I have three other solutions too:
>
> 1) Just write the HTML form manually and fill it in with dom helper functions. This has become my preference in a lot of cases, it is really easy.
>
> <form id="foo">
>   <input type="text" name="field" />
>   <textarea name="other"></textarea>
>   <select name="auto_list" data-options-from="some_backend_item"></select>
>   <select name="list">
>      <option value="whatever">Cool</option>
>   </select>
> </form>
>
> And so on and so forth. A lot of people don't like html, but I don't mind it at all; especially once you start using html5 attributes, it is fairly concise for this stuff.
>
> Another thing I like with this is the designer can write it with just a plain browser, no need for the whole backend infrastructure just to see some quick tweaks. Helps a lot when they are working offline too.
>
> Filling data is easy. Either use the functions directly:
>
> auto form = document.requireSelector!Form("#foo");
>
> foreach(k, v; your_data)
>    form.setValue(k, v);
>
>
> Or, if you are using my database.d with dom.d, relatively recent versions include a fillForm function:
>
> fillForm(form, your_object, "object_name"); // object_name is used if the function takes a struct rather than individual items - another relatively new feature
>
>
> To fill in data from a form, you can most easily use my DataObject class from database.d which doesn't take a hash constructor like Ruby but with foreach, it is close enough:
>
> auto obj = new DataObject(db, "table"); // you could subclass it for a specific table, database.d even has functions to generate those classes from MySQL CREATE TABLE declarations automatically
>
> foreach(k, v; cgi.post)
>    obj[k] = v;
>
> or you could easily enough list the expected keys in that filling loop, kinda like the Rails strong params (as I understand them - rails is now my day job but I'm still a bit of a n00b).
>
>
>
> Filling the form data and generating the model updates was the most painful part of writing PHP IMO, so dom.d made them all stupid simple. Now I don't feel the need for form helpers, the DOM is smart enough to fill in the gaps from whatever it is given.
>
> dom.d also has a function to get a value hash out of a form but I never actually used it. Maybe with local imports, I can make that smarter and selectively depend on cgi.d to actually have it cool. I gotta come back to this stuff some day.
>
>
> 2) Generate the HTML with the DOM library along with helper D functions to ensure more consistency.
>
> auto form = cast(Form) Element.make("form");
>
> form.addField("name", "value", [options]);
>
> addField has several overloads that pick the right HTML to make from a given data type. It generates consistent HTML for labels and spans so it is easy to style with CSS.
>
> But since this is D, it is a bit harder to pass to a HTML guy to edit the design. Otherwise though, dom.d's helper functions make all kinds of manipulations really easy and it is tempting to use more than I probably should.
>
>
> 3) Some hybrid, where you use custom tags in the HTML which are run. dom.d's more recent versions also include passing <%= %> and similar tags to a handler, if we really wanted to, we could use scripts there as well as custom tags and data attributes to fill things in.
>
> Early on, I used a LOT of custom tags, but nowadays I prefer to stick to mostly standard HTML so it works better stand alone.
>
>> The view uses appropriate names for the form fields, scoped in the same name as the model, like this:
>
> Yeah, that's pretty nice. database.d's fillData (on which dom.d's fillForm is based and web.d does the same for struct arguments) just uses dots:
>
> name="person.name"
>
> which would fill the
>
> void handler(Person person);
>
> person.name field there. Then you do person.toDatabaseObject (an auto-generated function btw) to get a SQL builder class out of it and modify it if you want then finally just person.commitChanges(); which is like Rails' .save!
>
> Perhaps I'll make the mixin just throw in a save method at some point too.
>
>
>
> This stuff is fairly new and underdocumented/advertised, even my by lax standards. I think this is the first time I've even talked about it on the forums.
>
>
> tbh from what I've seen, my collection of stuff is closer to the "full web framework" than vibe.d itself - as we discussed a couple months ago, I also have my SASS like css expander (which unlike the real sass doesn't need the rest of your life to recompile after any trivial change... though it is admittably still slow for D), javascript expanders and generators, various SQL backends, the list goes on.

Would you be interested in putting a web development framework (or parts of it) together we can tie in with vibe.d?
July 10, 2014
@Adam

At the moment, I'm looking into web development frameworks (from Foundation to CMSes to sever side solutions etc.), because in the months / years to come we (as in "the team I work in") will need a solid website.

Ideally, it would be PHP-free and not need much Javascript development (with Foundation you get some cool stuff via jQuery without having to bother with JS too much).

Your work on dom.d and web.d are a good starting point. What keeps me from using vibe.d + dom.d + web.d is the fact that it wouldn't be easy to transfer the tasks to someone who doesn't know D (= 99% of all web developers, I suppose). I cannot expect a web guy to learn D. However, I don't want to go down the same old PHP path again. PHP is inherently messy.*

*(How about interpreting JS through D as a server side language? Or something similar. Just thinking aloud).
July 10, 2014
On Thursday, 10 July 2014 at 13:55:14 UTC, Chris wrote:
> Would you be interested in putting a web development framework (or parts of it) together we can tie in with vibe.d?

Meh, not really. I've never used vibe.d so getting started is at least a psychological hurdle and I have a lot of other things to do too. I have considered doing a vibe backend for cgi.d before, which should be possible and maybe not even too hard, but just not far up on my priority list.

Many of my modules are made to stand alone though. Pulling dom.d in should be really easy, maybe database.d too (though since it uses C libraries to talk to the db server, it would probably cause problems with vibe's fibers; the queries would block the whole server).

web.d is really ugly code, it was my first serious usage of D's reflection and while it works, I'd love to rewrite it some day. I think I'd prefer to do web.d 2.0 before doing the vibe stuff.
July 10, 2014
On Thursday, 10 July 2014 at 14:50:50 UTC, Adam D. Ruppe wrote:
> On Thursday, 10 July 2014 at 13:55:14 UTC, Chris wrote:
>> Would you be interested in putting a web development framework (or parts of it) together we can tie in with vibe.d?
>
> Meh, not really. I've never used vibe.d so getting started is at least a psychological hurdle and I have a lot of other things to do too. I have considered doing a vibe backend for cgi.d before, which should be possible and maybe not even too hard, but just not far up on my priority list.
>
> Many of my modules are made to stand alone though. Pulling dom.d in should be really easy, maybe database.d too (though since it uses C libraries to talk to the db server, it would probably cause problems with vibe's fibers; the queries would block the whole server).
>
> web.d is really ugly code, it was my first serious usage of D's reflection and while it works, I'd love to rewrite it some day. I think I'd prefer to do web.d 2.0 before doing the vibe stuff.

I see.
July 10, 2014
On Thursday, 10 July 2014 at 14:15:19 UTC, Chris wrote:
> I cannot expect a web guy to learn D.

Why not? Most my actual usage code looks close enough to Java and sometimes even PHP that I think someone should be able to learn it easily enough to be useful...

> *(How about interpreting JS through D as a server side language? Or something similar. Just thinking aloud).

That kind of thing is possible, but it seems to me that if you are writing the code in javascript anyway you might as well just use one of the established players like node for that.