Many developers fall in love with the simplicity and expressiveness of Sinatra but quickly come to miss a great deal of functionality provided by other web frameworks such as Rails when building non-trivial applications.
Our team has come to love the philosophy of Sinatra which acts as a thin layer on top of rack allowing middleware to do most of the work and enabling additional complexity only when required.
The goal for this framework is to match the essence of Sinatra and make it suitable for increasingly complex applications that require the use of forms, mail delivery, localization, helpers, caching, etc…
For our team, coding is an art form and Sinatra best enables this concept because of these core principles:
The Padrino framework is the perfect solution for your small projects as well as for your larger project requirements!
Below we review a few ways that Padrino compares to existing web frameworks.
Like Sinatra, this framework uses http verb routing declarations instead of complex routing setups. We think that its more explicit, cleaner to read and simpler to write than other alternatives.
get "/home-page" do render :home end
Unlike Sinatra, this framework supports namespaced route aliases, named parameters, nested routes, and respond to formats. See the controller guide for more details.
Here is an example:
MyApp.controller :products do get :show, :map => "/this-is/:id/cool" do @product = Product.find(params[:id]) render 'products/show' end end
Route aliases can help you write urls in your app:
url(:products, :show, :id => product)
without consider the final url, because this may change.
In Rails, to do the same thing requires:
class ProductsController < ActionController::Base def show @product = Product.find(params[:id]) end end
Then open config/routes.rb and add a seo friendly url like:
map.connect "/this-is/:id/cool", :controller => "products", :action => "show"
With rails in order to establish the final url, we needed to open another file (config/routes.rb).
Figures to have: 50 controllers with 7 actions each.
At the end of your work you need to enhance your urls to be more SEO friendly …
You need to browse 50 controllers and check each action and copy/map them into routes.rb.
Different from Rails (and more similar to Merb), we take an explicit approach to rendering templates within a route. We believe that writing a little more can really help make the code much more readable.
In rails, you might see the following action:
class ClientsController < ActionController::Base def new @client = Client.new end end
To know which template will be rendered you need to know the name of the controller ClientsController or file name clients_controller.rb and be cognizant of conventions to know which template (/clients/new) will be rendered.
Now, we don’t think that you’re stupid. But especially in larger codebases or in code written from others your mind is needed elsewhere for more important things, so we enforce a concise syntax:
MyApp.controller :clients do get :new do @client = Client.new render 'clients/new' end end
For some this can be tiring to their hands, but for others it can help to understand better what exactly is going on. A little extra effort goes a long way!
We think that a framework must meet small projects and big projects requirements so for a thin app, a Rails tree maybe a too big, less clean and less concise.
Padrino’s generated tree is far more compact in comparison:
The main aim of Ruby and Rails is don’t repeat yourself but Padrino doesn’t just apply this concept for coding.
The current Rails version (things changed a little in 3.0 version) copies these for each project:
script/about script/breakpointer script/console script/dbconsole script/destroy script/generate script/performance script/plugin script/process script/runner script/server
Why do we need these commands for each project? With Padrino, you can achieve the same functionality with:
$ padrino start|stop # for starting and stopping the built-in server $ padrino-gen ... # that act as script/generate (can also use <tt>padrino g</tt>)
Why does each project need a Rakefile? How many times do you actually change it? In padrino, to run rake tasks you can simply do:
$ padrino rake your:task
If you need your own tasks like within rails, you can simply store them in lib/tasks and they will be automatically available to you. See the rake tasks guide for more info.
Both Merb and Rails still do not support a simple way (as within Django) to creating multiple applications within the same projects. Rails 3 is working towards true fully mountable applications, but Padrino has them right now out of the box and with virtually no extra effort.
Why is it necessary to have mountable applications? There are many different applicable scenarios. For example, you might need to build simple sites which act as customer showrooms. All of these sites share the same logic like admin, auths, models, etc.
In Rails, to achieve this you might normally create three separate applications:
$ rails show_room_1 $ rails show_room_2 $ rails show_room_3
Then if you are a good coder, you will have your own libs/gems and you can share them however you need to recreate models, migrations some custom helpers etc…
You might also see Rails apps with controllers such as:
/app/controllers/show_room_1 /app/controllers/show_room_2 /app/controllers/show_room_3
However, with this approach it becomes a little tricky to locate urls and generally more complicated to manage.
In Padrino, what Rails/Merb calls an Application is actually a Project. So following our simple scenario, you can create a project called showrooms and then build showroom applications mounted within the project.
$ padrino-gen project showrooms -r haml -d mongomapper # or your preferred orm $ cd showrooms $ padrino-gen app show_room_1 $ padrino-gen app show_room_2 $ padrino-gen app show_room_3
Then in your application you have a tree like:
As you can see this is a much cleaner and simpler to keep things organized within a large project requiring shared resources.
With Padrino, the developer is able to pick the best components based on the requirements of his project while still enjoying deep framework integration. In addition new components are easily added and are just a pull request away. For more information, check out the guides for more details.
Padrino is also capable of being included piece by piece into a standard Sinatra application if the entire framework is not needed. You can easily cherry pick the desired Padrino modules into a Sinatra app by following the standalone usage guide