Padrino 0.11.0 Released - Padrino Lives!
The Padrino team is very pleased to finally be able to announce the 0.11.0 release of the Padrino Framework! We have been working on this release for almost a year now and we have had dozens of contributors helping us stabilize Padrino. We know our release cycle got out whack and this version took too long to release. We all take accountability for that and will work to pick up release momentum and release patch and minor versions more often.
Since our 0.10.7 release, development on Padrino has been moving forward very actively and as such this is probably our biggest release in terms of code modified and issues resolved that we have had in years. We are very proud of this release which includes several major improvements:
1) Totally Redesigned Admin 2) New brand identity on the way 3) Upgraded Sinatra and http_router 4) CSRF Form Protection 5) ActiveSupport::SafeBuffer 6) New Rakefile format 7) Gemified Apps 8) Performance Tools 9) App Namespacing 10) Project Modules 11) Optimized Reloader
and a lot more changes! In the full post below, we will take you through a tour of the biggest changes in this release (for a more compact view, see our changelog).
Redesigned Admin
We have introduced a number of exciting improvements to admin in this release. First, with the help of @WaYdotNET, we have completely rewritten the admin interface front-end. The new front-end uses bootstrap, font-awesome and jQuery. A few commits: 1, 2
This snowballed into a huge team effort so thanks to everyone involved @WaYdotNET, @DAddYE, @dariocravero), @ujifgc, @tyabe and several others! Here’s a few screenshots of our brand new admin pages:
See more images in the Padrino Admin Album! Note that the new Padrino Admin has a responsive design that behaves well on tablets and mobile devices. Now you can even manage your admin data from your iPad!
There were also several additional fixes for admin listed below:
- Get the first key passed to expire helper. commit (Thanks @gugat)
- Fixes model output in erb templates. commit (Thanks @sleepingstu)
- Halting page with 404 if record is not found commit (Thanks @kot-begemot)
- Cleanups to admin documentation. commit (Thanks @danieltahara)
- Fixes CSS Errors on admin pages. commit (Thanks @dariocravero)
- A lot more commits, this was a huge effort!
New brand identity on the way
We have started to rebrand ourselves, thanks to @tomatuxtemple we are getting there!.. Welcome the new logo:
The new web experience is just around the corner too, so keep your eyes and ears wide open!
Upgraded Sinatra and http_router
Sinatra 1.4 was just released recently, and we have full support for Sinatra 1.4.X in this release. Commits: 1, 2, 3, 4, 5
We have also upgraded to the latest http_router 0.11 to address many thread-safety issues and overall performance improvements.
Thanks to @DAddYE for putting together the http_router upgrade to 0.11. Commits: 1
CSRF Protection
Padrino now supports CSRF protection out of the box to enable additional security protection against unauthorized commands being sent to a Padrino application.
Thanks to @skade and @dariocravero for working together to implement this security feature. Commits: 1, 2, 3, 4, 5
ActiveSupport::SafeBuffer
In Padrino 0.11.0, we have begun work on improving the security of Padrino out of the box. We all take app security very seriously, and after much discussion decided to introduce a SafeBuffer into Padrino. This will help protect users against XSS (Cross-site Scripting) attacks.
This change switches all rendering to use SafeBuffer instead of a raw string. All strings returned from #render are considered escaped. Strings can be marked safe for concatenation using String#html_safe, which turns returns the String as a SafeBuffer.
All helpers have been ported over to use SafeBuffers. The changes follow one general rule: all tag helpers like tag and content_tag escape everything by default while block helpers like content_for and form_for assume that the given content is already escaped.
If you are generating HTML in your helpers, you should now make sure that you call html_safe
on the result, so that the HTML is not automatically escaped:
def my_helper
"<p>hello!</p>".html_safe
end
Thanks to @skade for proposing and putting this together! See commits here: 1, 2, 3, 4
This is a direct port of the functionality present in Rails, so thanks to the whole Rails team as well.
New Rakefile format
Another source of frustration for users was the missing Rakefile
: now, every new project has one by default. `padrino rake` still continues to work, but bare `rake` works just as nice as well. Also, the Rakefile format has changed: instead of implicitly loading rake tasks that fit your environment, this is now explicit and looks like this:
require 'padrino-core/cli/rake'
PadrinoTasks.use(:sequel)
PadrinoTasks.use(:database)
PadrinoTasks.init
This makes it easier to replace tasks you don’t want to use and leads to less guessing by the framework. Don't like our database
tasks? Just erase that line. Want to use them again? Just put it back in.
Old Rakefiles still work, but will emit a very visible warning on how to change your Rakefile to the new format. Thanks to @skade for putting this together!
Gemified Apps
An often requested feature for Padrino is the ability to easily package a Padrino application as a gem. We have now baked this right into the project generator. If you want to generate an application for use as a gem, we will automatically generate the gem and project structure for you! Simply add the --gem
flag when generating a project:
padrino g project my_gemified_app --gem
This will generate a Padrino project within the context of a gem structure for you automatically. Now you can publish your Padrino apps as standalone gems with ease. After generation, see the README for more information about how to mount your gemified into Padrino projects.
A gemified project can be started and used like any other padrino project from its root path:
padrino start
But also be included into another project using the Gemfile
. For development, you can use the :path
option and the project will also be reloaded:
gem 'my_gemified_app' #, :path => /path/to/my_gemified_app
You can mount apps from other projects like so:
Padrino.mount('MyFancyApp::App', :app_file => MyGemifiedApp.root("my_fancy_app", "app.rb")).to('/my_fancy_app')
This is an exciting step for Padrino and creating truly standalone and modular applications that can be easily installed, setup and mounted into an existing Project. We have more plans for this as we approach towards 1.0.
Nothing keeps you from generating your main project as gemified project: there is nothing special about them, gemified projects behave like normal projects with some additions.
Thanks to @skade for putting this together! See commits here: 1, 2, 3, 4, 5
Performance Tools
In this release, we have also introduced a padrino-performance
gem optionally included as part of your Padrino application. Simply add padrino-performance
to your Gemfile. You can use the performance gem to check for well-know errors like multiple loaded json libraries on the console with:
bundle exec padrino-performance -j -- bundle exec padrino console
or profile the memory for your application:
bundle exec padrino-performance -m -- bundle exec padrino start
This represents the first step for our built-in memory and performance profiler within Padrino. This will get more love as we approach and move into our 1.0 release. We take performance and memory usage very seriously and are always striving to keep Padrino as lightweight as possible in line with our fast Sinatra foundations.
Thanks to @skade and @dariocravero for working together to get this to a solid place. You can find more details about this on the README and PR
App Namespacing
In addition to supporting gemified Padrino application, we have also taken another step towards modular design by introducing app namespacing. In the past, if a Padrino project was generated with the name “sample_blog”, then the application name would just be SampleBlog
.
Starting with 0.11.0, generated project now have namespaced apps within a module. For example, if you generate a Padrino project named “sample_blog” with:
padrino g project sample_blog --orm activerecord
The primary app file will still be located in “app/app.rb” but the class will be SampleBlog::App
. Similarly, everything else has been changed to support the namespacing to allow a project to be roughly self-contained within a single namespace.
One caveat is that to avoid any issues with various ORMs, models are not generated within the app namespace. Models will be continued to be generated outside of any namespace for simplicity.
Thanks to @achiu and Thanks to @skade for working together to finalize this and make this compatible with the new app gem support introduced as well.
Project Modules
Along with gemified apps, a new feature entered padrino-core: Project Modules. Those allow projects to live somewhere else then the applications root path and are a simple, yet powerful way of modularization. Project modules are tracked by the reloader and thus easy to use during development. A project module for a gemified app looks like this:
require 'padrino-core'
module GemifiedProject
extend Padrino::Module
gem! "gemified_project"
end
A project module will have its own root, so if you want to safely generate a path inside a gemified app, you should use the project module instead of Padrino
:
GemifiedProject.root("config", "database.rb")
Project Modules, like Padrino
have dependency_paths
to play around with that are tracked by the reloader:
GemifiedProject.dependency_paths << "#{MyModule.root}/uploaders/*.rb"
The nice thing is that gem!
is only a helper that indicates that this module should be loaded from a gem, along with proper tracking of the gems root path. You can also set up your own project module by hand, if you want to use some other form of organization. Just set the root
correctly:
module MyProject
extend Padrino::Module
self.root = "/my/fixed/folder"
end
You can use the Module for project namespacing, if you want to:
module MyProject
class MyModel
end
end
Optimized Reloader
As many of you might know, the Padrino development reloader has been a common point of frustration and trouble for us. There is still a ways to go and we have some plans on how to replace the reloader for 1.0. Still, in 0.10.7, the reloader would in certain cases for large projects become increasingly slow. In extreme cases, reloading could take as long as 10+ seconds.
Several people helped us track this down and the reloader is substantially faster in this release. The primary fix was thanks to @dcu who helped us clean up our traversal of object space and substantially speed of the reloader in extreme cases. commit. We also fixed a thread-safety issue thanks to @udzura. Thanks guys!
Upgraded Components
Several updated components in this release:
- Upgrade Mongoid to support 3.0. commit (Thanks @dcu)
- Fix mongoid rake tasks. commit (Thanks @dayflower)
- Add Puma as a server handler. commit (Thanks @dariocravero)
- Upgrade ActiveRecord support. commit
- Upgrade to mysql 2.8.1. commit (Thanks @udzura).
We are committed to keeping our support components up to date. We can always use help so pull requests welcome!
Mailer
- Lazy load mail gem for 20% padrino bootup speed improvement. commit (Thanks @ujifgc)
- Upgrade to mail gem 2.5.3 to fix security vulnerabilities. commit
- Refactor to cleanup and DRY code. commit (Thanks @Ortuna)
Logging
- Fix Padrino.logger thread safety issues. commits: 1, 2, 3 (Thanks @sgonyea)
- Add colorize_logging option. commit (Thanks @tyabe).
- Display seconds instead of milliseconds. commit (Thanks @muxcmux)
Helpers
- Add support for HTML5 multiple files upload. commit (Thanks @hooktstudios)
- Adds check_box_group and radio_button_group helpers commit (Thanks @ujifgc)
- Adds breadcrumbs helpers. commit (Thanks @WaYdotNET)
Cache Parser
We have also added a parser strategy pluggable interface for the padrino-cache. Now, you can select how the cache data is serialized into your cache store of choice. By default, we now store the data as plain text unless otherwise specified.
Example:
Padrino.cache = Padrino::Cache::File.new(...)
Padrino.cache.parser # => Padrino::Cache::Parser:Plain
Padrino.cache.parser = :marshal
Or you can write your own:
require 'oj'
module PadrinoJSON
def self.encode(code)
Oj.dump(code)
end
def self.decode(code)
Oj.load(code)
end
end
Finally you can load your strategy:
Padrino.cache.parser = PadrinoJSON
Thanks to @DAddYE for putting the parsing strategy system into place. commit
Bug Fixes
Lots of bug fixes and other changes in this release, see our changelog for a full rundown.
Explicit by default
A notable change comes in the philosophy of the framework: Instead of guessing application and task locations based on your bundle and project setup, Padrino will now use an explicit version (like setting the :app_file
parameter for Padrino.mount
and using PadrinoTasks.use
in Rakefiles). This makes it far easier for users to replace them and makes it clearer what gets loaded and what doesn't. It also avoids frustrating mis-guesses by the framework. The old ways will still work for quite a while, but we believe that less magic is the way to go in the future. This is no API change, the underlying API was always there, its just used in another way.
Summary
As we mentioned, this is probably one of the bigger releases we have had in a long time, but we will keep the momentum moving and probably be out with a 0.11.1 release in the next couple weeks. Please let us know if you run into any problems (especially when upgrading from 0.10.X).
There are a lot of people that have made this release happen. Thanks to @skade, @dariocravero, and @ujifgc from our core team for doing a lot of the contributions towards 0.11.0.
Special thanks to @wikimatze for cleaning up our docs and comments all over our framework and for putting together an awesome Padrino book that helps people learn how to use Padrino. Also special thanks to @postmodern for helping us out recently especially when it comes to security, @WaYdotNET for being a long time contributor plus helping redesign admin and @Ortuna for helping us to refactor and clean up our codebase. As always, Padrino 0.11.0 would not be possible without the support of Konstantin Haase and everyone else involved in Sinatra. Thanks to all of our contributors.
That concludes the changelog for this release. As always if you want to keep up with Padrino updates, be sure to follow us on twitter: @padrinorb, join us on IRC at “#padrino” on freenode or open an issue on GitHub.