tag:blogger.com,1999:blog-39504363252536639782024-02-20T05:17:40.003-08:00Another level of indirectionThis is a blog about refactoring/design with Ruby and Ruby on Rails.Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-3950436325253663978.post-22955520688996936652015-09-18T09:57:00.003-07:002015-09-18T10:07:01.448-07:00wkhtmltopdf config on Mac<div>
I ran into a snarl of a problem trying to get wkhtmltopdf working on my mac. The long of the short of it, these instructions (should) work. </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Get the right version installed via brew:</div>
<div>
<pre class="lang-rb prettyprint prettyprinted" style="background-color: #eeeeee; border: 0px; color: #393318; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; width: auto; word-wrap: normal;"><code style="border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; margin: 0px; padding: 0px; white-space: inherit;"><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">brew uninstall wkhtmltopdf
cd </span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">usr</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">local</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="typ" style="border: 0px; color: #2b91af; margin: 0px; padding: 0px;">Library</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="typ" style="border: 0px; color: #2b91af; margin: 0px; padding: 0px;">Formula</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">
git checkout </span><span class="lit" style="border: 0px; color: maroon; margin: 0px; padding: 0px;">https://gist.github.com/389944e2bcdba5424e01.git</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;"> </span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">usr</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">local</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="typ" style="border: 0px; color: #2b91af; margin: 0px; padding: 0px;">Library</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="typ" style="border: 0px; color: #2b91af; margin: 0px; padding: 0px;">Formula</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">/</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">wkhtmltopdf</span><span class="pun" style="border: 0px; color: black; margin: 0px; padding: 0px;">.</span><span class="pln" style="border: 0px; color: black; margin: 0px; padding: 0px;">rb
brew install wkhtmltopdf</span></code></pre>
</div>
<br />
WickedPDF needs to point to the development env properly:<br />
<br />
<pre style="background-color: #2b2b2b; color: #e6e1dc; font-family: Monaco; font-size: 18pt;"><span style="color: #bc9458; font-size: 18pt; font-style: italic;"># config/development.rb</span>
<span style="color: #6d9cbe;">WickedPdf</span>.config <span style="color: #cc7833;">= </span>{
<span style="color: #6d9cbe;">:</span><span style="background-color: #3c3c57; color: #6d9cbe;">exe_path</span><span style="color: #6d9cbe;"> </span><span style="color: #cc7833;">=> </span><span style="color: #a5c261;">"/usr/local/Cellar/wkhtmltopdf/0.9.9/bin/wkhtmltopdf"</span>,
<span style="color: #6d9cbe;">:root_url </span><span style="color: #cc7833;">=> </span><span style="color: #a5c261;">"http://localhost:3000"</span>}</pre>
<br />
<br />
Make sure you are not running a single threaded application server. In my cause configure unicorn:<br />
<br />
<pre style="background-color: #2b2b2b; color: #e6e1dc; font-family: Monaco; font-size: 18pt;"><span style="color: #bc9458; font-style: italic;"># config/unicorn.rb</span></pre>
<pre style="background-color: #2b2b2b; color: #e6e1dc; font-family: Monaco; font-size: 18pt;"><span style="color: #cc7833;">if </span><span style="color: #6d9cbe;">ENV</span>[<span style="color: #a5c261;">"RAILS_ENV"</span>] <span style="color: #cc7833;">== </span><span style="color: #a5c261;">"development"</span><span style="color: #a5c261;"> </span>worker_processes <span style="color: #a5c261;">3</span><span style="color: #a5c261;">
</span><span style="color: #cc7833;">end</span><span style="color: #cc7833;">
</span>timeout <span style="color: #a5c261;">30</span></pre>
<br />
And last but not least. I'm using RubyMine. Point the debugging environment to the unicorn config:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-uDaX4u4eh3Q/VfxCUFsnsZI/AAAAAAAABNo/hz7waUkGuYg/s1600/Screenshot%2B2015-09-18%2B12.55.14.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="http://4.bp.blogspot.com/-uDaX4u4eh3Q/VfxCUFsnsZI/AAAAAAAABNo/hz7waUkGuYg/s640/Screenshot%2B2015-09-18%2B12.55.14.png" width="640" /></a></div>
<br />
I hope this saves someone some time.<br />
<br />
Credits:<br />
http://stackoverflow.com/questions/12517640/why-does-pdfkit-wkhtmltopdf-hang-but-renders-pdf-as-expected-when-rails-app-is-k<br />
https://github.com/pdfkit/pdfkitAnonymousnoreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-59776414904493707282011-09-27T09:45:00.000-07:002015-10-23T08:40:54.210-07:00Rails exception handling - EgregiousVersion 0.2.9 released to https://rubygems.org/gems/egregious on 10.23.2015<br />
Added support for exceptions that define a http_status. The exception map can override this.<br />
This is a good way to allow a raise to specify a http_status using a custom exception.<br />
The idea for this came from the Stripe::Error exception classes.<br />
Also updated Gemfile.lock to ruby 2.2.1 and latest dependencies. This is for specs only.<br />
<div>
<br /></div>
Egregious is a rails based exception handling gem for well defined http exception handling for json, xml and html.<br />
<br />
If you have a json or xml api into your rails application, you probably have added your own exception handling to map exceptions to a http status and formatting your json and xml output. <br />
<br />
You probably have code sprinkled about like this:<br />
<pre class="ruby" name="code">rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = exception.message
respond_to do |format|
format.html { redirect_to dashboard_path }
format.xml { render :xml => exception.to_xml, :status => :forbidden }
format.json { render :json=> exception.to_json, :status => :forbidden }
end
end</pre>
<br />
This example is straight from the CanCan docs. You'll notice a couple of things here. This handles the CanCan::AccessDenied exception only. It then will redirect to the startup page, or render xml and json returning the http status code of :forbidden (403). You can see one of the first features of the Egregious gem. We extend Exception to add the to_xml and to_json methods. These return a well structured error that can be consumed by the API client.<br />
<pre class="ruby" name="code">Exception.new("Hi Mom").to_xml</pre>
<br />
returns: <br />
<pre class="ruby" name="code">"<errors><error>Hi Mom</error><type>Exception</type></errors>"</pre>
<br />
<pre class="ruby" name="code">Exception.new("Hi Dad").to_json</pre>
<br />
returns: <br />
<pre class="ruby" name="code">"{\"error\":\"Hi Dad\", \"type\":\"Exception\"}"</pre>
<br />
So that's pretty handy in itself. Now all exceptions have a json and xml api that describe them. It happens to be the same xml and json that is returned from the errors active record object, with the addition of the type element. That allows you to mix and match validations and exceptions. Wow, big deal. We'll it is. If you are writing a client then you need to have a very well defined error handling. I'd like to see all of rails do this by default. So that anyone interacting with a rails resource has a consistent error handling experience. (Expect more on being a good REST API in future posts.) As a client we can now handle errors in a consistent way.<br />
<br />
Besides the error message we would like a well defined mapping of classes of exceptions to http status codes. The idea is that if I get back a specific http status code then I can program against that 'class' of problems. For example if I know that what I did was because of invalid input from my user, I can display that message back to the user. They can correct it and continue down the path. But if the Http status code says that it was a problem with the server, then I know that I need to log it and notify someone to see how to resolve it.<br />
<br />
We handle all exceptions of a given class with a mapping to an http status code. With all the most common Ruby, Rails, Devise, Warden and CanCan exceptions having reasonable defaults. (Devise, Warden and CanCan are all optional and ignored if their gems are not installed.)<br />
<br />
As of 0.2.9 you can also define a method named 'http_status' on the exception and it will be used as the status code. This is a nice pattern that allows you to raise an exception and specify the status code. The Egregious::Error allows you to do this as a second parameter to initialize:<br />
<pre class="ruby" name="code">
raise Egregious::Error.new("My very bad error", :payment_required)
</pre>
<br />
If the problem was the api caller then the result codes are in the 300 range. If the problem was on the server then the status codes are in the 500 range. <br />
<br />
I'm guessing if you bother to read this far, you are probably interested in using Egregious. Its simple to use and configure. To install:<br />
<br />
In you Gemfile add the following:<br />
<pre class="ruby" name="code">gem 'egregious'</pre>
<br />
<br />
In your ApplicationController class add the following at or near the top:<br />
<pre class="ruby" name="code">class ApplicationController < ActionController::Base
include Egregious
protect_from_forgery
end
</pre>
<br />
<br />
That's it. You will now get reasonable api error handling.<br />
<br />
If you want to add your own exceptions to http status codes mappings, or change the defaults add an initializer and put the following into it:<br />
<pre class="ruby" name="code">Egregious.exception_codes.merge!({NameError => :bad_request})</pre>
<br />
Here you can re-map anything and you can add new mappings. <br />
<br />
Note: If you think the default exception mappings should be different, please contact me via the <a href="https://github.com/voomify/egregious">Egregious github project</a>.<br />
<br />
We also created exceptions for each of the http status codes, so that you can throw those exceptions in your code. Its an easy way to throw the right status code and setup a good message for it. If you want to provide more context, you can derive you own exceptions and add mappings for them.<br />
<br />
Here is an example of throwing a bad request exception: <br />
<pre class="ruby" name="code">raise Egregious::BadRequest.new("You can not created an order without a customer.") unless customer_id</pre>
<br />
<br />
Egregious adds mapping of many exceptions, if you have your own rescue_from handlers those will get invoked. You will not lose any existing behavior, but you also might not see the changes you expect until you remove or modify those rescue_from calls. At a minimum I suggest using the .to_xml and .to_json calls io your existing rescue_from methods/blocks.<br />
<br />
And finally if you don't like the default behavior. You can override any portion of it and change it to meet your needs.<br />
<br />
If you want to change the behavior then you can override the following methods in your ApplicationController.<br />
<pre class="ruby" name="code"># override this if you want your flash to behave differently
def egregious_flash(exception)
flash.now[:alert] = exception.message
end</pre>
<br />
<br />
<pre class="ruby" name="code"># override this if you want your logging to behave differently
def egregious_log(exception)
logger.fatal(
"\n\n" + exception.class.to_s + ' (' + exception.message.to_s + '):\n ' +
clean_backtrace(exception).join("\n ") +
"\n\n")
HoptoadNotifier.notify(exception) if defined?(HoptoadNotifier)
end</pre>
<br />
<br />
<pre class="ruby" name="code"># override this if you want to change your respond_to behavior
def egregious_respond_to(exception)
respond_to do |format|
status = status_code_for_exception(exception)
format.xml { render :xml=> exception.to_xml, :status => status }
format.json { render :json=> exception.to_json, :status => status }
# render the html page for the status we are returning it exists...if not then render the 500.html page.
format.html { render :file => File.exists?(build_html_file_path(status)) ?
build_html_file_path(status) : build_html_file_path('500')}
end
end</pre>
<br />
<br />
<pre class="ruby" name="code"># override this if you want to change what html static file gets returned.
def build_html_file_path(status)
File.expand_path(Rails.root, 'public', status + '.html')
end</pre>
<br />
<br />
<pre class="ruby" name="code"># override this if you want to control what gets sent to airbrake
# optionally you can configure the airbrake ignore list
def notify_airbrake(exception)
# for ancient clients - can probably remove
HoptoadNotifier.notify(exception) if defined?(HoptoadNotifier)
# tested with airbrake 3.1.15 and 4.2.1
env['airbrake.error_id'] = Airbrake.notify_or_ignore(exception) if defined?(Airbrake)
end</pre>
<br />
<br />
We are using this gem in all our Rails projects.<br />
<br />
Go forth and be egregious!Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-5896338788823777702011-08-08T08:25:00.000-07:002011-09-06T09:53:48.088-07:00Backbone.js and dependent selectsI had a fairly simple development task. Once I've done 20 different ways over the years. I have a select control with customers. When it changes I need to load the set of customer shipping addresses. The client code was a combination of jquery ajax calls and a custom client library for rendering/managing to server restful resources. Pretty quickly the code was getting messy! The problem seemed so easy, but the code did not reflect that. I decided to refactor it using <a href='http://documentcloud.github.com/backbone/'>backbone.js</a>. I'm going to show you how I solved this problem in this post. It will not cover the basics of <a href='http://documentcloud.github.com/backbone/'>backbone.js</a>. It will cover a simple use case and the design I came up with. It also covers some caveats I discovered with <a href='http://documentcloud.github.com/backbone/'>backbone.js</a>. <br /><br />Finally <a href='http://documentcloud.github.com/backbone/'>backbone.js</a> has entered my development toolkit. I was waiting for it without even knowing it. It addresses so many issues with typical client code development. <br /><br />If you don't know what Backbone is, then I suggest you visit <a href='http://documentcloud.github.com/backbone/'>backbone.js</a>. They have a number of tutorials. (Including this one.) The docs are solid. Once you bone up on the basics come on back. <br /><br />One of the first benefits was the code organization. With Backbone and <a href='http://documentcloud.github.com/jammit/'>Jammit</a> (for rails) I can layout a really nice development tree with each class in its own file. Here is the tree I currently have setup:<br /><br /><pre name="code" class="bash">├── app<br />│ ├── helpers<br />│ ├── models<br />│ │ └── collections<br />│ ├── templates<br />│ └── views<br />└── core<br /> ├── helpers<br /> ├── models<br /> ├── templates<br /> │ └── controls<br /> └── views<br /> └── controls</pre><br />I am able to have a 'core' set of helpers, models, templates, and views that are used across applications. This is not really a backbone feature, but because of backbone I setup <a href='http://documentcloud.github.com/jammit/'>Jammit</a> this way.<br /><br />The second thing I really loved was the clear separation between model and view. This just feels so natural having done the same thing on the server side for so many years. I'm going to assume you are familiar with the three basic backbone classes that I'm going to use: Model, Collection and View.<br /><br />Ok the problem is how to have one select change and then once the change occurs, populate another select with a collection based on the first selected. In my case I have the models 'Customer' and 'Address'. A customer has many shipping addresses. So every time a new customer is selected a different set of shipping addresses need to be loaded. <br /><br />Let's start by taking a look at the models (you'll see they are trivial).<br /><br /><pre name="code" class="javascript">App.Models.Customer = Backbone.Model.extend({});</pre><br /><br /><pre name="code" class="javascript">App.Models.Address = Backbone.Model.extend({});</pre><br /><br />Ok those were trivial. I like trivial. Now we will look at the collections. These are bound to our select controls.<br /><br /><pre name="code" class="javascript">App.Collections.Customers = Backbone.Collection.extend({<br /> model: App.Models.Customer,<br /> url: '/customers'<br />});</pre><br /><pre name="code" class="javascript">App.Collections.Addresses = Backbone.Collection.extend({<br /> model: App.Models.Address,<br /> url: '/addresses'<br />});</pre><br /><br />Again trivial. We tell the collection what our resource url looks like. <br /><br />Ok, now we get to the meat of the problem. The views. First I did was create a new view that can render a select based on a collection. It has a few other features I'll point out.<br /><br /><pre name="code" class="javascript">Core.Controls.Select = Backbone.View.extend({<br /><br /> initialize: function(){<br /> _.bindAll(this, 'render','value','triggerDependents','selectControl','startingIndex','addModel');<br /> this.selected = this.options.selected;<br /> this.dependent_views = this.options.dependent_views;<br /> // if the collection changes, re-renders<br /> this.collection.bind("all", this.render);<br /> this.render();<br /> },<br /> events:{<br /> "change": "triggerDependents"<br /> },<br /> defaults:{<br /> collection: [], // The collection to render<br /> selected: null, // The selected model<br /> dependent_views: []// The dependent views to notify on change<br /> },<br /> render: function(){<br /> this.el.html(JST.select(this));<br /> },<br /> selectControl: function() {return this.$("select");},<br /> value: function() { return this.selectControl().val();},<br /> // returns the starting index into the collection<br /> startingIndex: function(){<br /> var index = 0;<br /> if(this.options.blank)index = index +1;<br /> return index;<br /> },<br /> addModel: function(model,selected){<br /> if(selected)this.selected = model;<br /> this.collection.add(model);<br /> return this;<br /> },<br /> triggerDependents: function(event) {<br /><br /> if(this.selectControl().selectedIndex>=this.startingIndex())this.selected = this.collection.at(this.selectControl().selectedIndex-this.startingIndex());<br /> var _this = this;<br /> _.each(this.dependent_views,function(view){<br /> view.trigger(_this.id+"."+event.type, _this);<br /> });<br /> }<br />});<br /></pre><br /><br />Let's break this one done a little bit. Backbone has an initialize function that gets called after the object is created. In our initialize we do the following:<br /><br />First we use the underscore function that will ensure that when our function is called from an event somewhere, the this variable is setup as we expect it. In Ruby or other languages it is impossible to call an object without its self or this setup correctly. Javascript is like C. You can do objects, but they are not really first class citizens. Once you get used to these quirks they are quite serviceable. Second we pull out a couple of class attributes that we expect to be passed into the constructor. By default the constructor puts these into the <em>options</em> hash, because they are really core to our class we pull them up. This is a style thing. I left some other options in the hash, because they were not a fundamental data structure to our view. We then bind to our collection, so if anything changes on the collection it will all our render method and redraw our view. Finally we render the control.<br /><br />The next thing you see are two hashes: <em>events</em> and <em>defaults</em>. Events in views are jquery events and this hash is a shortcut for binding to them. We bind to the change event and call our function triggerDependents. Note: If you extend this 'class' and define an events hash it will take precedence over the base. The <em>defaults</em> hash is used to pre-populate the options with defaults. I've setup the collection and dependent_views as empty arrays (instead of null). I also setup select as null. Although null is not a very useful default , I think it documents what options the class will accept. <br /><br />Now in our render we are simply putting into the html element the results of our select template. We are using the _.template method from the underscore library and Jammit is managing the template loading and compilation. Let's take a look at the template:<br /><br /><script src="https://gist.github.com/1132170.js?file=select.jst"></script><br /><br />We are building the select control using the collection, selected and options passed in. <br /><br />So far so good. Nice and clean. <br /><br />I'm going to leave the rest of the select control as an exercise for the reader. I do want to point out the <em>triggerDependents</em> function. This will trigger the change event to any dependent_views passed into our constructor. It appends the id of the control so that a dependent view can listen to many controls and catch their events separately. We are using the event binding with backbone.js for this communication. This is independent from jquery events. it seems a little strange at first that they are not related, but the separation makes sense. If you have non-DOM events you want to trigger and handle, then use the model and view .bind and .trigger methods. The events hash does not route these non-dom events, so you have to bind to them in your initialize (or wherever is most appropriate.)<br /><br />OK so were are we at. We have a select control that will notify any dependent views when they are changed. I think we are ready to actually use them. Let's start with the select for customer addresses.<br /><br /><pre name="code" class="javascript">App.Views.CustomersAddressSelect = Core.Controls.Select.extend({ <br /> initialize: function(){<br /> Core.Controls.Select.prototype.initialize.call(this);<br /> this.bind("order_customer_id.change", this.loadAddresses);<br /> },<br /> loadAddresses: function(control){<br /> this.collection.reset();<br /> if(control.value()>0){<br /> this.collection.fetch({data: {"parent_key[customer_id]": control.value()}});<br /> }<br /> }<br />});</pre><br /><br />Here you see we are binding to the order_customer_id.change event that will get fired by the customer select. In response to this event we reset our collection. (This will cause a render that will disable the control, while we fetch the new records.) Then we fetch the addresses passing the parent key that our controller expects to filter the addresses. <br /><br />Note: From a security perspective you are going to want some server side check to make sure the given request is allowed to view the given records. That is clearly beyond the scope of this post!<br /><br />OK now to hook it all up we have the following:<br /><br /><pre name="code" class="javascript">$(function(){<br /> // our empty address collection<br /> var addresses = new App.Collections.Addresses([]);<br /> // Our dependent customer addresses select<br /> var shipping_address_select = new App.Views.CustomersAddressSelect({el: $('#ship_to_address_select'),<br /> id: 'order_shipping_address_id',<br /> name: 'order[ shipping_address_id]',<br /> collection: addresses});<br /> // Our customers collection - populated from the server<br /> var customers = new App.Collections.Customers(<%= raw select.collect{ |ct| {:name=>ct.name, :id=>ct.id}}.to_json %>);<br /> // The customer select, here we pass in the customers collection and the shipping_address_select dependent view.<br /> new Core.Controls.Select({el: $('#customer_select'),<br /> id: 'order_customer_id',<br /> name: 'order[customer_id]',<br /> collection: customers,<br /> blank: 'Select a customer',<br /> // set the shipping_address_select as dependent view<br /> // this will cause all events of the customer select to get<br /> // fired to the dependent controls with the id.event<br /> dependent_views:[shipping_address_select]});<br />});</pre><br /><br />Wow that looks pretty simple. We are doing a couple of things here to note: <br /><br /> This is a erb file that is building up the collection of customers on the server. Since we sourced this code from the server, we could save the round trip to fetch the customers. We could have fetched the customers from the client just as easily. <br /><br />We are binding to existing elements on the page by passing in <pre>el: $(selector)</pre>.<br /><br />We are passing in the shipping_address_select control as a dependent_view, this hooks up our notifications on change.<br /><br />Note: if you override the <em>events</em> hash in a derived class you will need to proxy any events that the base class was handling. In my case I ended up deriving a customer select class and wanted to listen to the change event. I lost my dependent view notifications, so in my change function I added a call to triggerDependents. I was not thrilled about this approach. I think preserving events in base classes would be a nice change for backbone.js.<br /><br />I hope you enjoyed this post. I loved working with Backbone.js and plan on building a full scale view library that makes all the crud operations easy as this.<br /><br />Cheers - RussellRxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com3tag:blogger.com,1999:blog-3950436325253663978.post-40088782192702252812011-02-14T13:54:00.000-08:002011-02-15T14:44:42.544-08:00Rails Stack on OS XI just got a new MacBook Pro. I spent so much time creating recipes for our production deployment stack, I wanted to reuse that effort. I also wanted a consistent stack from all developers. When I looked around I found <a href="https://github.com/atmos/smeagol">smeagol</a> and <a href="https://github.com/atmos/cinderella">cinderella</a>. They were close, but of course the stack I wanted was different. Then I found <a href="http://github.com/mathie/chef-homebrew">chef-homebrew</a>. This fit the bill perfectly. I could now use my existing recipes (adapted slightly for OS X). So I created a public project that does just that. It provides a default rails stack on OS X. It works with a clean OS X install. Your mileage may vary. <br /><br />First thing first is to install CodeX from the installation DVD. It is in the Optional Install. (You can register on the apple site and download it, but the download is 3.4 GB.) <br /><br />git clone git://github.com/voomify/strudel.git<br />cd strudel<br />rake strudel:installRxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-62651947669963797942010-05-13T06:26:00.001-07:002010-05-13T06:47:08.191-07:00Rails 3, Gems, Rake and BundlerI ran into a bit of a mystery the other day. I have a new rails 3 (beta3) install. <br /><br />I'm using Jeweler to build a new gem using Rake. When I install the gem using Rake all goes along as expected. If I go to the command line and type <strong>gem list</strong>. My gem does not show up. After digging around I found that the gem is getting installed into the <strong>~/.bundler</strong> gem location.<br /><br />If I run gem commands from the terminal then <strong>GEM_HOME</strong> is as I set it.<br />If I run gem commands from inside Rake (for my Rails 3 project that has had bundler install run on it) then it is using <strong>~/.bundler/..</strong> as the root of <strong>GEM_HOME</strong>.<br /><br />As a result I have a gem that i need to install and re-install a lot. So I have to execute the gem uninstall commands from inside Rake.<br /><br />Here is what my rake file looks like now:<br /><script src="http://gist.github.com/399849.js?file=gistfile1.txt"></script>Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-72270051509925110962010-05-10T11:46:00.000-07:002010-05-13T06:59:45.113-07:00Rails 3 templates and engines<div><br />What I really wanted to do was to setup a rails 3 environment that uses engines to organize modular functionality.<br /><br />It has ALWAYS been my experience that any project will quickly get out of hand if the organization is not tackled very early. Rails projects get messy fast. If you are disciplined enough to use modules for functionality then you can avoid some of these issues. But I really don't like having module names that I have to use spread out in my code. (Albeit sometimes a module to separate functionality is the best course of action.) I've always wanted to have my own app namespace for my functionality boundaries. Wouldn't this be nice:<br /></div><br /><script src="http://gist.github.com/396378.js"></script><br /><div><br />With plugins I got closer. With the gemifcation I got a little help packaging my plugins up and defining dependencies.<br /><br />Then came along the rails engines plugin. I have to admit I liked it, but never felt comfortable diving in. The reason is that engine plugins required a fair amount of twidling bits in rails to get it working right. Whenever that happens I feel a little exposed. (Not that that is always a bad thing!) We'll good news for me...I waited long enough and rails 3 (and rails 2.3 as well) has engines as first class citizens.<br /><br />I've spend a few days pushing them around and I like it. With a little work I was able to create some rails templates that will generate a new rails engine. I then configure the hosting app Gemfile to include my engine and I'm off and running. Nice!<br /><br />I thought I'd share the work I've done for those that want to do something similar.<br /><br />NOTE: All these samples are for postgres and rspec. On testing, there are many options out there. I happen to dig rspec, if you have not tried it you should. If you care about your data you will stop using mysql or sqllite and start using postgres. <br /><br />You can find the templates @ <a href="http://github.com/voomify/voomify/templates">http://github.com/voomify/voomify/templates</a>.<br />(Warning they reference each other using a local path, so you will need to change that if you plan on using them for yourself. You can create a directory ~/dev/voomify/templates and put the templates there and they will work for you.)<br /><br />If you have not checked out templates for rails 2.3 and rails 3 then you should do some reading. This is not a tutorial. Here are some references to get started with:<br /><a href="http://m.onkey.org/2008/12/4/rails-templates">http://m.onkey.org/2008/12/4/rails-templates</a><br /><a href="http://asciicasts.com/episodes/148-app-templates-in-rails-2-3">http://asciicasts.com/episodes/148-app-templates-in-rails-2-3</a><br /><a href="http://benscofield.com/2009/09/application-templates-in-rails-3/">http://benscofield.com/2009/09/application-templates-in-rails-3/</a><br /><br />Here are some sample templates that really helped me get started:<br /><a href="http://github.com/jm/rails-templates">http://github.com/jm/rails-templates</a><br /><br />So what do these templates do? Well there are three templates:<br />1) app.rb - this creates a rails application with rspec and sets it up to be compatible with our engines.<br />2) engine.rb - this creates a rails application that is also an engine.<br />3) finailize.rb - this finalizes our application or engine. It is always called at the end of the process.<br /></div><br /><br />I then created a litle bash script that will make it easy for me to call these.<br /><br />Normally I have to put together a long command line:<br /><script src="http://gist.github.com/396415.js"></script><br /><br />With this bash script (in ~/.bashrc on ubuntu):<br /><script src="http://gist.github.com/396410.js"></script><br />Credit for this goes to: Ryan Bates (http://asciicasts.com/episodes/148-app-templates-in-rails-2-3)<br /><br />My command line is now much simpler (whew!):<br /><script src="http://gist.github.com/396412.js"></script><br /><br />OK time to get cooking. First let's create a rails 3 engine. This engine will be embedded in our application container. It will be setup with rspec and all the proper '.gitignore' files. It will prompt you for the engine name and the database username. (It also adds jeweler to the app gems. We need this because our engines use jeweler to gemify themselves. Maybe in a later post I will figure out how to remove this dependency.)<br /><br />Side Note: With rails 3 you no longer have to do that messy 'script/generate rspec_XXXX' junk anymore. Rspec is now installed as the default generator and you can simply run 'rails g scaffold ...'. I dig it.<br /><br /><script src="http://gist.github.com/396445.js"></script><br /><br />Now let's add some job scaffolding:<br /><br /><script src="http://gist.github.com/396476.js?file=gistfile1.txt"></script><br /><br />The way these engines are setup they are also full blown applications that we can test inside. This way we develop the engine functionality just like we are in any other application. We can run generators, write tests the way we are accustom to. From your perspective it is just a rails app. How easy is that?<br /><br />Now let's see it running like any other rails app:<br /><br /><script src="http://gist.github.com/396528.js?file=gistfile1.txt"></script><br /><br />Let's goto the jobs and see them in action: <a href="http://localhost:3000/jobs">http://localhost:3000/jobs</a><br /><br />Before we embed this we need to create a gem.<br /><script src="http://gist.github.com/396484.js?file=gistfile1.txt"></script><br /><br />Ok let's embed this into our 'host' application.<br /><br />Generate the host application:<br /><br /><script src="http://gist.github.com/396458.js"></script><br /><br />Add the following to your Gemfile:<br /><br /><script src="http://gist.github.com/396472.js?file=gistfile1.txt"></script><br /><br />Ok now for migrations. We don't have any helpers for migrations yet. So for now you need to copy your engine migration into your app. Something like this:<br /><br /><script src="http://gist.github.com/396465.js?file=gistfile1.txt"></script><br /><br />Now startup your 'host' app and you will see your jobs. Nice! Imagine how modular you could be! Like a lego version of your coding self.<br /><br /><script src="http://gist.github.com/396456.js?file=gistfile1.txt"></script><br /><br />Let's goto the jobs and see them embedded inside our application as a rails 3 engine!: <a href="http://localhost:3000/jobs">http://localhost:3000/jobs</a><br /><br /><br />Using the voomify-jobs.gemspec in the jobs engine directory you can specify gem depenencies. So if your engine depends on other gems you just need to add them here. That includes other engines. Now you can explicitly manage your dependencies. I feel so clean ... you?<br /><br />Happy engines.<br /><br />Note: I ran into a bundler, rake, gem install issue that I cover in this post:<br /><a href="http://railsindirection.blogspot.com/2010/05/rails-3-gems-rake-and-bundler.html">Rails 3, Gems, Rake and Bundler</a>Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-39182550474363620052010-05-07T20:52:00.000-07:002010-05-09T21:31:47.625-07:00Setting Rails 3 Beta on Ubuntu 9.10I spent some time trying to get rails 3 beta 2 running on Ubuntu.<br />The default gem install using apt-get is 1.3.5.<br />For rails 3 you will need gem 1.3.6.<br /><br />Install RubyGems 1.3.6<br /><script src="http://gist.github.com/395669.js"></script><br /><br />OK now you are ready to follow the rails guide:<br /><a href="http://weblog.rubyonrails.org/2010/2/5/rails-3-0-beta-release/">http://weblog.rubyonrails.org/2010/2/5/rails-3-0-beta-release/</a><br /><br />Ok Now to install rspec:<br />If you don't have xmllib already setup you will get errors building nokogiri. Follow these to fix that:<br /><br /><a href="http://nokogiri.org/tutorials/installing_nokogiri.html">http://nokogiri.org/tutorials/installing_nokogiri.html</a><br /><br />Then install rspec-rails 2.0:<br /><a href="http://github.com/rspec/rspec-rails">http://github.com/rspec/rspec-rails</a><br /><br />Happy Rails 3 Riding!Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-4239281437020239902010-02-23T08:26:00.000-08:002010-02-23T08:35:00.232-08:00Vendor rails and svnWe are using SVN and vendoring Rails. Everytime we update to a new version of rails it requires a bunch of deletes and adds. We do this for multiple projects. It is a pain. So I finally bit the bullet and decided to create a repository area for rails version. In our tree we put our rails versions off our trunk like the following:<br /><br />/etorg/trunk/rails/rails-2.3.5<br /><br />Then we us svn:externals with the path in the vendor directory.<br /><br />The trick (and the reason I'm writing this down) is that to keep svn from either complaining with a warning or giving an error was to move the original vendor/rails directory to another name 'vendor/dead_rails' then commit. That results in no conflicts or warnings.<br /><br />I hope this saves someone some head scratching time.Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-29688638882816179122009-05-10T20:54:00.000-07:002009-06-17T10:41:19.664-07:00Erector - ruby CRUD viewsIn my last post I created a simple Erector view with a layout and talked about the pro's and con's of using a ruby class based view. Before we go any further I want to re-establish that I'm not a fan of markup. So if you are a markup jockey ... then you might want to move on. This Object Oriented view business is probably not your cup of tea. After all who would want clean, testable code in their views? Besides me that is.<br /><br />OK you decided that you care enough about your views to read on. Stick with it, its worth the ride.<br /><br />Let's get started by using the default scaffolding to generate a customer model. Run the following:<br /><br /><pre class='code'><code><br />script/generate scaffold customer first_name:string, last_name:string, company:string, phone:string, email:string<br /></code></pre><br /><br />Then run the migration and test the pages.<br /><pre class='code'><code><br />rake db:migrate<br /></code></pre><br /><br />Now lets turn these views into erector views. Erector comes with a tool that will turn your erb's into erector classes. Run the following from your application root directory:<br /><pre class='code'><code><br />erector app/views/customers/**<br /></code></pre><br />If you look in your views/customers directory you will now see .rb files. Let's compare the code. Here is our show.html.erb:<br /><br /><pre class='code'><code><br /><p><br /> <b>First name:</b><br /> <%=h @customer.first_name %><br /></p><br /><br /><p><br /> <b>Last name:</b><br /> <%=h @customer.last_name %><br /></p><br /><br /><p><br /> <b>Company:</b><br /> <%=h @customer.company %><br /></p><br /><br /><p><br /> <b>Phone:</b><br /> <%=h @customer.phone %><br /></p><br /><br /><p><br /> <b>Email:</b><br /> <%=h @customer.email %><br /></p><br /><br /><br /><%= link_to 'Edit', edit_customer_path(@customer) %> |<br /><%= link_to 'Back', customers_path %><br /></code></pre><br /><br />Now here is the erector equivalent: <br /><br /><pre class='code'><code><br />class Views::Customers::Show < Erector::Widget<br /> def content<br /> p do<br /> b do<br /> text 'First name:'<br /> end<br /> text @customer.first_name<br /> end<br /> p do<br /> b do<br /> text 'Last name:'<br /> end<br /> text @customer.last_name<br /> end<br /> p do<br /> b do<br /> text 'Company:'<br /> end<br /> text @customer.company<br /> end<br /> p do<br /> b do<br /> text 'Phone:'<br /> end<br /> text @customer.phone<br /> end<br /> p do<br /> b do<br /> text 'Email:'<br /> end<br /> text @customer.email<br /> end<br /> rawtext link_to('Edit', edit_customer_path(@customer))<br /> text '|'<br /> rawtext link_to('Back', customers_path)<br /> end<br />end<br /></code></pre><br /><br />It is pretty straight forward. One gotcha is that the base class is the <br />Erector::Widget class. The problem is that we are using rails helper and these are exposed using the Erector::RailsWidget base class. You can either change the base class to Erector::RailsWidget or you can introduce an erector layout that derives from Erector::RailsWidget and then you would derive from your layout class. (See my last post for more info on this.) The other thing you need to do is to move or destroy the erb files. If you don't move or delete them then your new erector view classes will not be found. Now you have erector views for your scaffolded customer. Take it for a spin.<br /><br />I personally think the syntax is cleaner if we use the {} block syntax instead of do end. Here is the same view re-written to use {}:<br /><br /><pre class='code'><code><br />class Views::Customers::Show < Erector::Widget<br /> def content<br /> p {<br /> b {text 'First name:'}<br /> text @customer.first_name<br /> }<br /> p {<br /> b {text 'Last name:'}<br /> text @customer.last_name<br /> }<br /> p {<br /> b {text 'Company:'}<br /> text @customer.company<br /> }<br /> p {<br /> b {text 'Phone:'}<br /> text @customer.phone<br /> }<br /> p {<br /> b {text 'Email:'}<br /> text @customer.email<br /> }<br /> rawtext link_to('Edit', edit_customer_path(@customer))<br /> text '|'<br /> rawtext link_to('Back', customers_path)<br /> end<br />end<br /></code></pre><br /><br />Now you have a feel for what it looks like. How about a quick refactor of this code. I personally don't like the hard coded labels, so let's remove that:<br /><br /><pre class='code'><code><br />class Views::Customers::Show < Erector::Widget<br /> <br /> def show_column(col)<br /> p {<br /> b {text col.to_s.titleize }<br /> text @customer[col]<br /> }<br /> end<br /> <br /> def content<br /> show_column :first_name <br /> show_column :last_name<br /> show_column :company<br /> show_column :phone<br /> show_column :email<br /> <br /> rawtext link_to('Edit', edit_customer_path(@customer))<br /> text '|'<br /> rawtext link_to('Back', customers_path)<br /> end <br />end<br /></code></pre><br /><br />Now that's what I'm talking about. Now gee, if i do that in all my show views, I can easily refactor that method and make it available in either a base class or a module mix-in. What I like is how easy the refactoring is. It feels as it should easy.<br /><br /><h3>Rawtext and text</h3><br />You'll notice that we output using either text or rawtext. The difference is text is escaped and rawtext is not.Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com1tag:blogger.com,1999:blog-3950436325253663978.post-50211973804951521132009-05-10T09:38:00.000-07:002009-05-10T13:12:59.584-07:00Erector - Object Oriented viewsI just got back from railsconf. On the plane ride home I decided to take a look at <a href="http://erector.rubyforge.org/userguide.html">Erector</a>. Erector, besides having a cool name, is a dsl for writing markup. It is very similar to markaby, except erector views are not templates, they are plain old ruby objects. Let's look at an example:<br /><pre class='code'><code><br />class Views::Home::Index < Views::Layouts::Application<br /> def main_content<br /> h1 'Welcome to Voomify'<br /> p do<br /> text 'What is Voomify?'<br /> end<br /> p "Voomify is the verb for applying Voom to a problem."<br /> <br /> p "Voom as defined by Dr Seuss in 'The Cat in the Hat Comes Back':"<br /> <br /> blockquote do<br /> p "'Voom is so hard to get,<br /> You never saw anything<br /> Like it, I bet.<br /> Why, Voom cleans up anything<br /> Clean as can be!'"<br /> <br /> p "Then he yelled,<br /> 'Take your hat off now,<br /> Little Cat Z!<br /> Take the Voom off your head!<br /> Make it clean up the snow!<br /> Hurry! You Little Cat!<br /> One! Two! Three! GO!'"<br /> <br /> p "Then the Voom...<br /> It went VOOM!<br /> And, oh boy! What a VOOM!"<br /> <br /> <br /> p "Now, don't ask me what Voom is.<br /> I never will know.<br /> But, boy! Let me tell you<br /> It DOES clean up snow!"<br /> end<br /> <br /> end<br />end<br /></code></pre><br /><br />This will render the following code:<br /><br /><pre class='code'><code><br /><h1>Welcome to Voomify</h1><p>What is Voomify?</p><p>Voomify is the verb for applying Voom to a problem.</p><p>Voom as defined by Dr Seuss in 'The Cat in the Hat Comes Back':</p><blockquote><p>'Voom is so hard to get,<br /> You never saw anything<br /> Like it, I bet.<br /> Why, Voom cleans up anything<br /> Clean as can be!'</p><p>Then he yelled,<br /> 'Take your hat off now,<br /> Little Cat Z!<br /> Take the Voom off your head!<br /> Make it clean up the snow!<br /> Hurry! You Little Cat!<br /> One! Two! Three! GO!'</p><p>Then the Voom...<br /> It went VOOM!<br /> And, oh boy! What a VOOM!</p><p>Now, don't ask me what Voom is.<br /> I never will know.<br /> But, boy! Let me tell you<br /> It DOES clean up snow!</p></blockquote><br /></code></pre><br /><br /><br />Admittedly this is not a very good example showing any benefit at all to using Erector. It is all markup and requires no real logic at all. Be patient we'll eventually get there.<br /><br /><br />Why would anyone want to do that? We'll for one I hate markup. (When I'm in full markup mode, i feel dirty.) If you love markup and erbs, then you should stop reading now. Before you leave, I'll leave you with this, you can easily mix erector and erbs (or any other template that works with rails). Some tasks are very well suited to markup and others are better suited to a markup dsl. If you are tag heavy then you should stick with your erb's. If you find you views are light with markup but heavy with ruby flow and control logic then erector or markaby may be the ticket. <br /><br /><h3>Markaby or Erector</h3><br /><br />I dont' know much about Markaby. After taking Erector for a spin, I took a closer look at Markaby. I like it. The biggest difference to me is that Markaby allows you to create ruby template files the same way erb's do. The views are still templates with ruby syntax. They are not first class ruby objects. With erector they are first class plain old ruby objects. Why is this good? It gives you all the tools of inheritance and mixin's for your views. That is cool. Especially for an application with multiple views of the same underlying models. You can refactor your views into base classes that derive and render the same data in different ways. This is object oriented design for views. Nice.<br /><br /><br /><h3>Side Note</h3><br /><br />I've seen object oriented view code in other languages and it leads to some very powerful re-use that all OO programmers can understand. The most ambitious of these attemps was by an HR company named Seeker in the bay area. I was working for Concur at the time and we bought Seeker back in 1999. (It did not work out well, but that is a story for another time.) Seeker created their own markup language that was object oriented. The nature of HR data is that it has very complicated rules regarding who can see what data and when. The OO design of the language allowed that to be abstracted to the base classes and a functional programmer simply focused on the problem at hand. They took it further, as all commercial enterprise applications do, and they allowed the customer to define new models and views. Those views were very easy to write with this advanced data access logic abstracted out. Their customers loved it. They wrote very advanced business applications on top of this abstraction.<br /><br /><br /><h3>A Closer Look</h3><br /><br />So let's look a little deeper at using Erector with rails. Follow the erector installation and you'll be able to write an erector view. One gotcha I ran into was the fact that your views should derive from Erector::RailsWidget. If you don't do that you don't have access to the rails helpers.<br /><br /><h3>To layout or not to layout</h3><br /><br />You have a couple of options for the layout. You can keep your erb layout and just drop in your Erector views. That is cool if you have an app already that you want to mix erector into quickly. It also allows the views to be rendered with different layouts.<br /><br /><br />The other option is to create an Erector layout. If you do that then you set your controler like so:<br /><br /><pre class='code'><code><br />class HomeController < ApplicationController<br /> layout nil<br />...<br /></code></pre><br /><br />Here is a simple erector layout:<br /><br /><pre class='code'><code><br />class Views::Layouts::Application < Erector::RailsWidget<br /> def javascript_includes <br /> javascript_include_tag 'application' <br /> end<br /><br /> def stylesheet_includes<br /> stylesheet_link_tag 'styles' <br /> end<br /><br /> def header<br /> h1 'Voomify'<br /> end<br /><br /> # override this to render your view 'main' content<br /> def main_content <br /> end<br /> <br /> def footer <br /> a 'Home', :href=>"/"<br /> end<br /><br /> <br /> def content<br /> <br /> html do<br /> head do<br /> title "Voomify"<br /> javascript_includes<br /> stylesheet_includes<br /> end<br /> body do <br /> <br /> div :id=>"maincontainer" do <br /><br /> div :id=>"contentwrapper" do<br /> div :id=>"topsection" do<br /> header<br /> end<br /> <br /> div :id=>"contentcolumn" do<br /> main_content<br /> end<br /> div :id=>"footer" do<br /> footer <br /> end<br /> end <br /> end<br /> end<br /> end <br /> end<br />end<br /></code></pre><br /><br /><br /><br />Then you derive your view from the layout erector class. The view example above does just that. Notice that the view defined above implements main_content. This is the method defined by our layout, you can name it whatever you want. You'll also notice that it has methods to override for the header, footer, javascript_includes and stylesheet_includes. So if the page want's to modify any of those elements all it needs to do is override those methods. It can call super if it wants or just replace it.<br /><br /><br />This got me thinking about the decoupled relationship between templates and their view. The view does not know anything about where they are being rendered. Generally this is a very good thing. For example a view may be rendered on a page, or as an ajax call. Coupling the view to the layout creates a tight dependency between the two. This troubled me at first. (OK not that much, the world has bigger problems!) But then I started thinking about it. How often do I have single view that has a different layout? Not much. When I do with Erector I could use a decorator pattern from my base layout. OK that works. What about ajax forms? I have not tried it yet, but I'm pretty sure I can call my main_content to return to an ajax request. <br /><br /><br /><br />OK so not very often do I have multiple layout variations with the same view. What does happen a lot is that I would like to make a modification to how the layout renders based on the view. Eventually the layout ends up with conditionals that render some of the erb if some variable is set by the controller. Yuck! How many times have you done that. (Be honest!) You say to yourself its ugly, but it's a template. You grit your teeth and move on. Or if it really bothers you, you introduce a helper, but it suffers from the same condition, branching logic, but now its written in ruby. An Object Oriented layout can easily eliminate that. Another case is when a view participates in another relationship. For example a given view may be related to other models in the system. The layout defines a standard layout for this relationship and then the view code implements main_content and related_content. The related_content method could return markup, or the layout may take care of the markup, and all the related content needs to do is return the model objects that are related to my current view. <br /><br /><br />In my next post I'll be building a simple contact model and then turning it into an Erector set of views. Until then ... keep it clean.Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-61221078499191892902009-05-07T09:00:00.000-07:002009-05-10T08:01:56.186-07:00Railsconf 09 -VegasHere are my takes on the railsconf 09. It was my first railsconf. I've attended many JavaOne and MSFT PDC's, dating back to 1990. What struck me most was the enthusiasm of the community. You get that vibe in general, but to see a ballroom full of rails enthusiasts is another story.<br /><br />In Java and MSFT events they are pushing new technology, even when it is barely baked. I expected this railsconf to do the same with rails 3, but there was not much content talking about rails 3. DHH did spend his keynote talking about some major highlights. My take is that rails 3 will be more elegant, flexible and performant, but the migration will be painful.<br /><br />At the keynote DHH opened up talking about the attacks on rails. He was telling his on story about how he came to understand they were not personal attacks and it really just did not matter. It made me realize how early stage the rails community really is.(I'm not talking about the technology, but the community.) The vibe is: the rails world has been growing, but is it grown up enough to become a major player? You can especially hear it when people start talking about enterprise rails. Those conversations always start with a justification of how rails is ready. <br /><br />The rails community at large is a passionate group that believes they have a better way of doing things. (Even if it is not entirely true.) It has a rebel feeling. I love that. The rails community needs to own its success. Strut around with more confidence. (BTW I'm NOT saying DHH does not have confidence!) Getting early adopters to use it is easy, getting wide spread adoption is much harder. Right now it still feels like early adoption. I'm not sure the rails community wants wide spread adoption. Careful for what you wish for.<br /><br />Other highlights for me:<br />* Obie Fernandez being so passionate and honest about what he and hash rocket have gone through.<br />* Jim Weirich - Writing Modular Applications. Jim did a great job outlining a taxonomy for describing dependencies. The base material dates back to the 80's.<br />* Pen & Teller - They rock.Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-10244906773303296322009-04-28T19:49:00.000-07:002009-05-10T07:08:36.670-07:00DRY views using builders - AKA markup sucksIn this post I'm taking a look at how to DRY the view code from the <a href='http://guides.rubyonrails.org/getting_started.html'>Getting Started with Rails</a><br /><br />The first thing I noticed about the Getting Started Guide was that the mark-up was really not very dry, so the question became how can I dry up the mark-up? OK so it does use a partial for the shared edit and new form. It has been my experience that most forms and lists are pretty simple and should not need this much mark-up. Truth be told, I hate writing mark-up. So how can I describe the presentation with enough detail so that I don't have to write so much? Don't get me wrong I don't mind writing mark-up that is unique for a given page. Just don't make me write more form and table markup...please.<br /><br />So we want to be dry, cool. But we also want to be DRO (don't repeat others). So who is solving this problem? Let's start with our forms. How to DRY our forms. A quick look around a common pattern appears: Use Builders. A builder allows an application to emit custom code for a given form field. Were going to examine the formtastic plugin:<br />* http://github.com/justinfrench/formtastic/tree/master<br /><br />In our case we would like to write simple erb code that emits all the tags for our form. In keeping with our DRO model we are going to take the formtastic plugin for a spin and see what we get.<br /><br />First thing is to install the formtastic plugin:<br /><br /><pre class='code'><code><br />script/plugin install git://github.com/justinfrench/formtastic.git <br /></code></pre><br /><br />Now let's see if we can update the _form.html.erb file using formtastic:<br /><br /><pre class='code'><code><br /><% @post.tags.build if @post.tags.empty? %><br /><% form_for(@post) do |post_form| %><br /> <%= post_form.error_messages %><br /> <p><br /> <%= post_form.label :name %><br/><br /> <%= post_form.text_field :name %><br /> </p><br /> <p><br /> <%= post_form.label :title, "title" %><br/><br /> <%= post_form.text_field :title %><br /> </p><br /> <p> <br /> <%= post_form.label :content %><br/><br /> <%= post_form.text_area :content %><br /> </p><br /> <h2>Tags</h2><br /> <% post_form.fields_for :tags do |tag_form| %><br /> <p><br /> <%= tag_form.label :name, 'Tag:' %><br /> <%= tag_form.text_field :name %><br /> </p><br /> <% unless tag_form.object.nil? || tag_form.object.new_record? %><br /> <p><br /> <%= tag_form.label :_delete, 'Remove:' %><br /> <%= tag_form.check_box :_delete %><br /> </p><br /> <% end %><br /> <% end %><br /> <p><br /> <%= post_form.submit "Save" %><br /> </p><br /><% end %> <br /></code></pre><br /><br />With our new form builder we can dry this up a little bit:<br /><pre class='code'><code><br /><% @post.tags.build if @post.tags.empty? %><br /><br /><% semantic_form_for(@post) do |post_form| %><br /> <%= post_form.error_messages %><br /> <%= form.inputs %><br /><br /> <h2>Tags</h2><br /> <% post_form.fields_for :tags do |tag_form| %><br /> <p><br /> <%= tag_form.label :name, 'Tag:' %><br /> <%= tag_form.text_field :name %><br /> </p><br /> <% unless tag_form.object.nil? || tag_form.object.new_record? %><br /> <p><br /> <%= tag_form.label :_delete, 'Remove:' %><br /> <%= tag_form.check_box :_delete %><br /> </p><br /> <% end %><br /> <% end %><br /> <%= form.buttons %><br /><% end %> <br /></code></pre><br /><br />A couple of things to notice when you run this. You now have some more view logic that was provided by formtastic. Required fields are marked on the form with an *. The form is now drawn with a fieldset. The form uses left justified labels. If you look at the browswer source you'll also notice that it uses a <ol>> elements. (This is why the fields are numbered.) The form fields tags now have classes and id's for all the tags. <br /><br />OK that went pretty well..so let's go a step further and refactor the tags:<br /><pre class='code'><code><br /><% @post.tags.build if @post.tags.empty? %><br /><% semantic_form_for(@post) do |post_form| %><br /> <%= post_form.inputs %><br /> <% post_form.semantic_fields_for :tags do |tag_form| %><br /> <% tag_form.inputs :name, :name => 'Tags' do %><br /> <%= tag_form.input :name %><br /> <% unless tag_form.object.nil? || tag_form.object.new_record? %><br /> <%= tag_form.input :_delete, :as=>:boolean, :label => 'Remove:' %> <br /> <% end %><br /> <% end %><br /> <% end %><br /> <%= post_form.buttons %><br /><% end %> <br /></code></pre><br /><br />Now we are getting somewhere! No mark-up! I could get use to doing forms like this.<br /><br />My next implementation step is to generate client side validations by reading the model validations and presenting them at input time. Check out the <a href='http://livevalidation.rubyforge.org/'>livevalidation plugin</a>Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0tag:blogger.com,1999:blog-3950436325253663978.post-17095357409184088592009-04-17T07:12:00.000-07:002009-04-17T08:57:18.604-07:00All great journeys start with one step<p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Like most of you that came to Ruby on Rails. I was excited to see what this promising framework could do for productivity. Before Rails I had designed large scale commercial web applications on both C++ and Java. My real specialty was to define the framework and then extend it as the application demands. We wanted our code to be DRY (before everyone was using the term DRY). A good framework adds structure, is easy to understand, is easy to extend and eliminates repetitive code. Rails certainly lives up to my definition of a good framework. It handles many of the most common issues that teams building data driven web applications have to solve. Ruby is the giant's shoulders that Rails stands on. The language is so expressive and dynamic it creates so many possibilities. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Now it is time for a small trip down architecture memory lane. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">I've been developing data driven web applications since 1996. Looking back on it is seems archaic. At the time we were forging new ground. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Version 1.0 1996: We created one of the earliest commercial, dynamic, configurable, web based business applications. One thing that made these applications so effective is that they were massively configurable by the clients. Everything, and I mean everything, could be customized by the client. Back then the tools were non-existent. Our first application was MSFT based. Good old fashion COM objects talking to ASP 1.0. We developed a model layer with the COM objects and the ASP programmers then consumed them to present the view. It was a simple MV design. (No controller.) HTML was so limited back then, so we had a java applet that handled the advanced data entry UI. This essentially had to mimic what we had built as a windows application. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Version 2.0 1997: We designed a JavaScript version that eliminated the 'heavy' Java applet from the client. This was a very ambitious multiplatform JavaScript library. It had to understand a very rich meta-data layer that described how the data entry for the client should behave. The DOM was not very rich and if you wanted to dynamically do much of anything on the client you had to write it from scratch and then make it work on all the browsers.</span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Version 3.0 1998: So far these applications were installed by large fortune 500 businesses. But it was too complicated to setup and maintain for a midsize company. So we introduced the Software as a Service (SaaS). Back then we called it ASP or our Hosted business. This introduced a whole bunch of new design challenges. Should there be one database per customer or larger databases shared with a 'domain' column partitioning the data. How do you manage it? How do you scale it? How do you secure it. This is before really anyone else had a viable SaaS product much less business model.</span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Version 3.0 2001: The success of all the earlier projects led to more customers with even more needs. This time they need to have a global solution that could handle many languages simultaneously. Like many code bases the investment into refactoring the original design was borrowed from for years. As a result it never really evolved as it could have. By now the tools had advanced very far. Java (J2EE) was leading the charge with MSFT 'embracing and 'extending' with .Net. We had already switched to Java (J2EE) and built a very cool XML driven B2B product that integrated suppliers in the procurement chain. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">So it was time to build the mother of all projects. It had a list of requirements that would scare off most engineers. </span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">We started with a simple J2EE stack layered with a bunch of Apache technologies.<span style="mso-spacerun:yes"> </span>We chose Turbine as our MVC. Our model layer was based on Torque.<span style="mso-spacerun:yes"> </span>Torque was great for navigating the model, insert, updates, deletes and transactions.<span style="mso-spacerun:yes"> </span>But our views were often hitting many tables and a pedestrian Torque implementation would result in too many database round trips.<span style="mso-spacerun:yes"> </span>So we introduced our own read only data access layer RDAL (Rapid Data Access Layer). <span style="mso-spacerun:yes"> </span>RDAL allowed us to write portable SQL and get very efficient data-access out of the system all while looking like a Torque model object to the view. <span style="mso-spacerun:yes"> </span>We considered JSP, ECS and Struts for the view layer.<span style="mso-spacerun:yes"> </span>In the end we decided against all of them to selected Velocity.<span style="mso-spacerun:yes"> </span>What attracted me to Velocity was the simplicity of the templating language.<span style="mso-spacerun:yes"> </span>It could do what you normally need to do in a view very well, loop, conditionals.<span style="mso-spacerun:yes"> </span>It was not expressive enough to put logic into the view.<span style="mso-spacerun:yes"> </span>We could re-use snippets of code with it (like a Rails partial).<span style="mso-spacerun:yes"> </span>Essentially what we had was a J2EE/Apache MVC stack that did much of what you find in Rails. <span style="mso-spacerun:yes"> </span></span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">So now we had an application framework, big deal.<span style="mso-spacerun:yes"> </span>We were building database driven web applications.<span style="mso-spacerun:yes"> </span>So we have a lot of CRUD operations to deal with.<span style="mso-spacerun:yes"> </span>Those CRUD interfaces all had to deal with the following:<o:p></o:p></span></p> <p class="MsoListParagraphCxSpFirst" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">It was a SaaS offering so every CRUD set of views had to be domain aware.<o:p></o:p></span></p> <p class="MsoListParagraphCxSpMiddle" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">Most CRUD views had to support custom fields <o:p></o:p></span></p> <p class="MsoListParagraphCxSpMiddle" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">Every view had to be multi-lingual with multiple users viewing the site in different languages simultaneously.<o:p></o:p></span></p> <p class="MsoListParagraphCxSpMiddle" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">Views had to support role based behavior.<span style="mso-spacerun:yes"> </span>(Be aware of the role of the current user and present different options based on their role.)<o:p></o:p></span></p> <p class="MsoListParagraphCxSpMiddle" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">It was a SaaS application so it had to be VERY secure.<span style="mso-spacerun:yes"> </span>We chose to implement the OWASP security standards for the application.<o:p></o:p></span></p> <p class="MsoListParagraphCxSpLast" style="margin-top:0in;margin-right:0in; margin-bottom:0in;margin-left:1.0in;margin-bottom:.0001pt;mso-add-space:auto; text-indent:-.25in;line-height:normal;mso-list:l0 level1 lfo1"><span style="font-size:8.0pt;font-family:Symbol;mso-fareast-font-family:Symbol; mso-bidi-font-family:Symbol;color:black"><span style="mso-list:Ignore">·<span style="font:7.0pt "Times New Roman""> </span></span></span><span style="font-size:8.0pt;font-family:"Georgia","serif"; mso-fareast-font-family:"Times New Roman";mso-bidi-font-family:"Times New Roman"; color:black">Every view could be customized by an consulting engineer.<span style="mso-spacerun:yes"> </span>That customization would override the default view behavior on a per-customer basis.<span style="mso-spacerun:yes"> </span>The consults should also be able to add new views for that client.</span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Dang that’s a lot of stuff each developer has to be concerned about.<span style="mso-spacerun:yes"> </span>Where to start? The view layer really does nothing to provide any productivity to solve any of these problems.<span style="mso-spacerun:yes"> </span>If you want to build a new or edit form you have to write a whole bunch of form html.<span style="mso-spacerun:yes"> </span>If you wanted a list you would have to write a bunch of table markup.<span style="mso-spacerun:yes"> </span>So the question became how do you DRY up the view and meet the requirements above?<span style="mso-spacerun:yes"> </span></span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">Our answer was to introduce a presentation markup language.<span style="mso-spacerun:yes"> </span>You would describe your model in the markup and it would generate a CRUD set of views for you that does all of the above automatically.<span style="mso-spacerun:yes"> </span>It was really easy to add new CRUD views on a given model.<span style="mso-spacerun:yes"> </span>It was easy to change the UI design for a given element.<span style="mso-spacerun:yes"> </span>We had a UI designer that would introduce new behavior as we progressed on the project.<span style="mso-spacerun:yes"> </span>We could modify all the views built so far with this new UI behavior.<span style="mso-spacerun:yes"> </span>Did I mention that it would generate tests for you as well? It was slick as snot.</span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">The presentation markup was concerned only with how you want to render the model(s).<span style="mso-spacerun:yes"> </span>From the markup you could embed velocity code just like a partial.<span style="mso-spacerun:yes"> </span>You could call java ‘helper’ methods.<span style="mso-spacerun:yes"> </span>It allowed us to have declarative UI for much of the system.<span style="mso-spacerun:yes"> </span></span></p> <p class="MsoNormal" style="margin-bottom:0in;margin-bottom:.0001pt;line-height: normal"><span style="font-size:8.0pt;font-family:"Georgia","serif";mso-fareast-font-family: "Times New Roman";mso-bidi-font-family:"Times New Roman";color:black">This blog is will follow along as I solve the same problem, extending the rails framework along the way. <o:p></o:p></span></p>Rxhttp://www.blogger.com/profile/06910543674058958983noreply@blogger.com0