Rails 4 links compilation
Posted by santiago.pastorino
on November 13, 2012
I'm leaving here a curated compilation of interesting links where you will find information that is not very well known. There are pull requests, issues, commits, examples, posts, videos and more about Rails 4.
I'm also giving a shout out asking for improvements to this compilation. If you find something is missing or you have suggestions to make let me know by commenting in this post.
The Rails Guides are not always enough. When you don't find something in the guides or docs, you probably search for information on the internet or a blog post about the specific subject. But wouldn't it be better if you had all the related information together? This could also be a great starting point for a new Rails guide.
So, I encourage everyone to help compiling more material about each new section of Rails 4 and then, by looking at all this compilation, start guides about specific topics. You can do that by directly pushing to [docrails](http://github.com/lifo/docrails), which has public access for everyone to push documentation changes only.
[](/images/posts/Rails4-4.png)
## Overview
- [Ruby on Rails Guides: Rails 4.0 Release Notes](http://edgeguides.rubyonrails.org/4_0_release_notes.html)
- [Rails 4 in 30'](http://blog.wyeworks.com/2012/10/29/rails-4-in-30-minutes/)
- [Why should I care about Rails 4](http://vimeo.com/51898266)
- [Rails 4 and the Future of Web](http://confreaks.com/videos/1228-aloharuby2012-keynote-rails-4-and-the-future-of-web)
- [Rails 4 Whirlwind Tour](http://vimeo.com/51181496)
- [BostonRB: what to expect in Rails 4.0](http://bostonrb.org/presentations/what-to-expect-in-rails-40)
- [Rails 4 Countdown to 2013](http://blog.remarkablelabs.com/2012/11/rails-4-countdown-to-2013)
## Upgrade
- Ruby 1.9.3
- [Commit](https://github.com/rails/rails/commit/4fa615a8661eb13d4bd8a7de4d839e9883ef26ec)
- [Rails 4 Countdown to 2013 - Rails 4 requires at least Ruby 1.9.3](http://blog.remarkablelabs.com/2012/12/rails-4-requires-at-least-ruby-1-9-3-rails-4-countdown-to-2013)
- New deprecation policy
- [Weblog Post mentions deprecation policy](http://weblog.rubyonrails.org/2012/8/9/ann-rails-3-2-8-has-been-released/)
- vendor/plugins has gone
- [Commit](https://github.com/rails/rails/commit/dad7fdc5734a3813246f238ac5760b2076932216)
- [Rails 4 Countdown to 2013 - Rails::Plugin reaches end of life](http://blog.remarkablelabs.com/2012/12/rails-plugin-reaches-end-of-life-rails-4-countdown-to-2013)
- Moved to a plugin
- Hash-based & Dynamic finder methods
- [Gem](https://github.com/rails/activerecord-deprecated_finders)
- Mass assignment in AR models
- [Gem](https://github.com/rails/protected_attributes)
- ActiveRecord::SessionStore
- [Gem](https://github.com/rails/activerecord-session_store)
- [Commit](https://github.com/rails/rails/commit/0ffe19056c8e8b2f9ae9d487b896cad2ce9387ad)
- [Rails 4 Countdown to 2013 - ActiveRecord::SessionStore Gem Extraction](http://blog.remarkablelabs.com/2012/12/activerecord-sessionstore-gem-extraction-rails-4-countdown-to-2013)
- ActiveResource
- [Gem](https://github.com/rails/activeresource)
- [ActiveResource is dead, long live ActiveResource](http://yetimedia.tumblr.com/post/35233051627/activeresource-is-dead-long-live-activeresource)
- [Rails 4 Countdown to 2013 - ActiveResource Gem Extraction](http://blog.remarkablelabs.com/2012/12/activeresource-gem-extraction-rails-4-countdown-to-2013)
- Action Caching
- [Gem](https://github.com/rails/actionpack-action_caching)
- Page Caching
- [Gem](https://github.com/rails/actionpack-page_caching)
- Page and Action Caching
- [Rails 4 Countdown to 2013 - Page and Action Caching Gem Extraction](http://blog.remarkablelabs.com/2012/12/page-caching-action-caching-gem-extraction-rails-4-countdown-to-2013)
- New default test locations
- [Pull Request](https://github.com/rails/rails/pull/7878)
- Observers
- [Gem](https://github.com/rails/rails-observers)
- [Commit](https://github.com/rails/rails/commit/ccecab3ba950a288b61a516bf9b6962e384aae0b)
- [Rails 4 Countdown to 2013 - Observers Gem Extraction](http://blog.remarkablelabs.com/2012/12/observers-gem-extraction-rails-4-countdown-to-2013)
## Active Support
- Queue API (NOTE: This was reverted and will be included in Rails 4.1)
- [Commit](https://github.com/rails/rails/commit/adff4a706a5d7ad18ef05303461e1a0d848bd662)
- [Rails 4 Countdown to 2013 - Rails.queue](http://blog.remarkablelabs.com/2012/12/rails-queue-rails-4-countdown-to-2013)
- Notifiers start & finish
- [Commits](https://github.com/rails/rails/compare/60736fe...c7847f1)
- Dalli replaces memcache-client
- [Rails 4 Countdown to 2013 - Dalli replaces memcache-client](http://blog.remarkablelabs.com/2012/12/dalli-replaces-memcache-client-rails-4-countdown-to-2013)
## Action Mailer
- Asynchronous Mailer (NOTE: This was reverted and will be included in Rails 4.1)
- [Pull Request](https://github.com/rails/rails/pull/6839)
- [Rails 4 Countdown to 2013 - Asynchronous Action Mailer](http://blog.remarkablelabs.com/2012/12/asynchronous-action-mailer-rails-4-countdown-to-2013)
## Active Model
- ActiveModel::Model
- [Plataforma: barebone models to use with actionpack in rails 4.0](http://blog.plataformatec.com.br/2012/03/barebone-models-to-use-with-actionpack-in-rails-4-0/)
- [Commit](https://github.com/rails/rails/commit/3b822e91d1a6c4eab0064989bbd07aae3a6d0d08)
- [Rails 4 Countdown to 2013 - ActiveModel::Model](http://blog.remarkablelabs.com/2012/12/activemodel-model-rails-4-countdown-to-2013)
- ActiveModel Validator
- [Rails 4 Countdown to 2013 - ActiveModel Absence Validator](http://blog.remarkablelabs.com/2012/12/activemodel-absence-validator-rails-4-countdown-to-2013)
## Action Pack
- ActionController::Live
- [Aaron Patterson's blog post: Is it Live](http://tenderlovemaking.com/2012/07/30/is-it-live.html)
- [Why Rails 4 Live Streaming is a big deal](http://blog.phusion.nl/2012/08/03/why-rails-4-live-streaming-is-a-big-deal/)
- [Commit](https://github.com/rails/rails/commit/af0a9f9eefaee3a8120cfd8d05cbc431af376da3)
- [Rails 4 Countdown to 2013 - Live Streaming](http://blog.remarkablelabs.com/2012/12/live-streaming-rails-4-countdown-to-2013)
- Strong parameters
- [Gem](https://github.com/rails/strong_parameters)
- [Parameters Security Tour](http://iconoclastlabs.com/cms/blog/posts/upgrading-to-rails-4-parameters-security-tour)
- [Ruby on Rails Weblog: Strong parameters](http://weblog.rubyonrails.org/2012/3/21/strong-parameters/)
- [Rails 4 Quick Look: Strong Parameters](http://rubysource.com/rails-4-quick-look-strong-parameters/)
- [Pull Request](https://github.com/rails/rails/pull/7251)
- [Railscast](http://railscasts.com/episodes/371-strong-parameters)
- [Rails 4 Countdown to 2013 - Strong Parameters](http://blog.remarkablelabs.com/2012/12/strong-parameters-rails-4-countdown-to-2013)
- Turbolinks
- [Gem](https://github.com/rails/turbolinks)
- [Introducing Turbolinks for Rails 4.0 geekmonkey](http://geekmonkey.org/articles/28-introducing-turbolinks-for-rails-4-0)
- [Turbolinks benchmarks from Steve Klabnik](http://blog.steveklabnik.com/posts/2012-09-27-seriously--numbers--use-them-)
- [Railscast](http://railscasts.com/episodes/390-turbolinks)
- [Rails 4 Countdown to 2013 - Turbolinks](http://blog.remarkablelabs.com/2012/12/turbolinks-rails-4-countdown-to-2013)
- Russian Doll Caching
- [How key-based cache expiration works](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works)
- [Evening on Backbone.js/ Q&A with dhh](http://www.youtube.com/watch?v=FkLVl3gpJP4#t=33m30s)
- [Rails 4 Countdown to 2013 - Russian Doll Caching & Cache Digests](http://blog.remarkablelabs.com/2012/12/russian-doll-caching-cache-digests-rails-4-countdown-to-2013)
- Cache Digests
- [Gem](https://github.com/rails/cache_digests)
- [Commit](https://github.com/rails/rails/commit/502d5e24e28b3634910495d0fb71cb20b1426aee)
- [Railscast](http://railscasts.com/episodes/387-cache-digests)
- Declarative ETags
- [Gem](https://github.com/rails/etagger)
- [Commit](https://github.com/rails/rails/commit/ed5c938fa36995f06d4917d9543ba78ed506bb8d)
- [Rails 4 Countdown to 2013 - Generate Controller-Wide ETags](http://blog.remarkablelabs.com/2012/12/generate-controller-wide-etags-rails-4-countdown-to-2013)
- Decouple Action Pack and Action View
- [Pull Request](https://github.com/rails/rails/pull/7356)
- Asset Pipelining
- [Moving forward with the Rails asset pipeline](http://yetimedia.tumblr.com/post/33320732456/moving-forward-with-the-rails-asset-pipeline)
- sprockets-rails
- [Gem](https://github.com/rails/sprockets-rails)
- [Extraction](https://github.com/rails/rails/pull/5409)
- [Rails 4 Countdown to 2013 - Sprockets Rails](http://blog.remarkablelabs.com/2012/12/sprockets-rails-rails-4-countdown-to-2013)
- Replace memcache-client with dalli
- [Pull Request](https://github.com/rails/rails/pull/6903)
- Routing Concerns
- [Gem](https://github.com/rails/routing_concerns)
- [Commit](https://github.com/rails/rails/commit/0dd24728a088fcb4ae616bb5d62734aca5276b1b)
- [Rails 4 Countdown to 2013 - Routing Concerns](http://blog.remarkablelabs.com/2012/12/routing-concerns-rails-4-countdown-to-2013)
- PATCH verb
- [Weblog post](http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/)
- [Rails issue: use PATCH verb instead of PUT](https://github.com/rails/rails/issues/348)
- [Rails 4 Countdown to 2013 - HTTP PATCH Verb](http://blog.remarkablelabs.com/2012/12/http-patch-verb-rails-4-countdown-to-2013)
- Rename all action callbacks from \*\_filter to \*\_action
- [Commit](https://github.com/rails/rails/commit/9d62e04838f01f5589fa50b0baa480d60c815e2c)
- [Rails 4 Countdown to 2013 - Renaming \*\_filter to \*\_action](http://blog.remarkablelabs.com/2012/12/renaming-_filter-to-_action-rails-4-countdown-to-2013)
- Helpers
- [HTML5 tag helpers - Pull Request](https://github.com/rails/rails/pull/6359)
- [Rails 4 Countdown to 2013 - Collection Form Helpers](http://blog.remarkablelabs.com/2012/12/collection-form-helpers-rails-4-countdown-to-2013)
- [Rails 4 Countdown to 2013 - New HTML5 Form Input Helpers](http://blog.remarkablelabs.com/2012/12/new-html5-form-input-helpers-rails-4-countdown-to-2013)
- Render default index page
- [Pull Request](https://github.com/rails/rails/pull/8468)
- [Rails 4 Countdown to 2013 - Dynamic index.html](http://blog.remarkablelabs.com/2012/12/dynamic-index-html-rails-4-countdown-to-2013)
- Register your flash types
- [Rails 4 Countdown to 2013 - Register your own flash types](http://blog.remarkablelabs.com/2012/12/register-your-own-flash-types-rails-4-countdown-to-2013)
- [Commit](https://github.com/rails/rails/commit/238a4253bf229377b686bfcecc63dda2b59cff8f)
- New exceptions pages for development
- [Pull Request](https://github.com/rails/rails/pull/8668)
## Active Record
- What's new
- [Rails 4 Countdown to 2013 - What's new in Active Record](http://blog.remarkablelabs.com/2012/12/what-s-new-in-active-record-rails-4-countdown-to-2013)
- MySQL strict mode by default
- [Pull Request](https://github.com/rails/rails/pull/6069)
- PostgreSQL support
- [Rails 4 Countdown to 2013 - A love affair with PostgreSQL](http://blog.remarkablelabs.com/2012/12/a-love-affair-with-postgresql-rails-4-countdown-to-2013)
- Support for array datatype in PostgreSQL
- [Rails 4.0 sneak peek: PostgreSQL array support](http://reefpoints.dockyard.com/ruby/2012/09/18/rails-4-sneak-peek-postgresql-array-support.html)
- [Pull Request](https://github.com/rails/rails/pull/7547)
- Support for MACADDR, INET, CIDR datatypes in PostgreSQL
- [Rails 4.0 sneak peek: PostgreSQL MACADDR, INET, CIDR support](http://reefpoints.dockyard.com/ruby/2012/05/18/rails-4-sneak-peek-expanded-activerecord-support-for-postgresql-datatype.html)
- Support for specifying transaction isolation level
- [Commit](https://github.com/rails/rails/commit/392eeecc11a291e406db927a18b75f41b2658253)
- Schema cache dump
- [Pull Request](https://github.com/rails/rails/pull/5162)
- [Rails 4 Countdown to 2013 - Schema Cache Dump](http://blog.remarkablelabs.com/2012/12/schema-cache-dump-rails-4-countdown-to-2013)
- ActiveRecord::Relation bang methods
- [Commit](https://github.com/rails/rails/commit/8c2c60511beaad05a218e73c4918ab89fb1804f0)
- ActiveRecord::Base.all returns a Relation
- [Commit](https://github.com/rails/rails/commit/6a81ccd69d96f36f4322ef927191ab5a35e68d68)
- Relation#find\_or\_create\_by and friends
- [Commit](https://github.com/rails/rails/commit/eb72e62c3042c0df989d951b1d12291395ebdb8e)
- CollectionProxy#scope
- [Commit](https://github.com/rails/rails/commit/0e1cafcbc4d67854faf35e489571bc30f5e2ac14)
- Support for partial inserts
- [Commit](https://github.com/rails/rails/commit/144e8691cbfb8bba77f18cfe68d5e7fd48887f5e)
- Relation.where with no args can be chained with not
- [Pull Request](https://github.com/rails/rails/pull/8332)
- [Revert of like and not\_like](https://github.com/rails/rails/commit/8d02afeaee8993bd0fde69687fdd9bf30921e805)
- [Rails 4 Countdown to 2013 - Not Equal support for Active Record queries](http://blog.remarkablelabs.com/2012/12/not-equal-support-for-active-record-queries-rails-4-countdown-to-2013)
- Add metadata to schema\_migrations table
- [Pull Request](https://github.com/rails/rails/pull/8399)
- Rename update\_attributes method to update, keep update\_attributes as an alias
- [Commit](https://github.com/rails/rails/commit/1f3a1fedf951dbc4b72d178e2a649c4afd2f1566)
## Railties
- Threadsafe on by default
- [Aaron Patterson's blog post](http://tenderlovemaking.com/2012/06/18/removing-config-threadsafe.html)
- [Discusion of Tony Arcieri's Pull Request](https://github.com/rails/rails/pull/6685)
- [Improve eager load on Rails: Pull Request](http://github.com/rails/rails/pull/7225)
- [Railscast](http://railscasts.com/episodes/365-thread-safety)
- [Rails 4 Countdown to 2013 - Rails 4 is thread safe by default](http://blog.remarkablelabs.com/2012/12/rails-4-is-thread-safe-by-default-rails-4-countdown-to-2013)
- Binstubs
- [Install binstubs by default](https://github.com/rails/rails/commit/f34c27a452418d8aa17f92bb0fd7ae97b5f7e252)
- [Revert "Install binstubs by default"](https://github.com/rails/rails/commit/1e9d6e7b567c778baa884e7e569e67cdf5040119)
- [Revert "Ignore /bin on new apps" -- given the move to default binstubs, we want you to check those in!](https://github.com/rails/rails/commit/61b91c4c55bcbd5a2ec85d6e1c67755150653dff)
- [bundle binstubs \](https://github.com/carlhuda/bundler/compare/17561867...885ed215)
- [Understanding binstubs](https://github.com/sstephenson/rbenv/wiki/Understanding-binstubs)
- Add --no-html to scaffold generator
- [Commit](https://github.com/rails/rails/commit/cb025f850c45f26355892961d5cf05145d247a4d)
- Rails commands
- [Commands](https://github.com/rails/commands)
- [Spring](https://github.com/jonleighton/spring)
## Security
- Default headers
- [Security Guide's default headers](http://edgeguides.rubyonrails.org/security.html#default-headers)
- match doesn't catch all
- [Commit](https://github.com/rails/rails/commit/56cdc81c08b1847c5c1f699810a8c3b9ac3715a6)
- Set escaping HTML in JSON encoding to true by default
- [Pull Request](https://github.com/rails/rails/pull/6287)
- Add ActiveSupport::KeyGenerator as a simple wrapper around PBKDF2
- [Pull Request](https://github.com/rails/rails/pull/6952)
- Encrypted Cookies + Sign using Derived Keys
- [Pull Request](https://github.com/rails/rails/pull/8112)
Please send me more information about Rails 4 if you find that I'm missing something in this post.
P.D.: Thanks to Nikolay Petrachkov who gave me a starting point for building this list and to Guillermo Iguaran who contributed reviewing and sharing some links too.
Rails 4 in 30'
Posted by santiago.pastorino
on October 29, 2012
I gave a presentation in [RubyConf Argentina](http://rubyconfargentina.org/en) about what's new in Rails 4 (if you saw it please [rate it](http://speakerrate.com/talks/17941-rails-4-en-30)). I've already posted the [Rails 4 MindNode](http://blog.wyeworks.com/2012/9/20/rails-4-in-a-mindnode/) which I used to start to think about what I was going to present. The talk was in Spanish but I'm leaving here the English version of the slides.
If you want to use these slides to spread the word about what's new in Rails you don't need to ask me for permission, just feel free to use them and make the changes you want. I would appreciate a mention in your presentation and all the suggestions you may have for improving the slides and/or the mind map.
I still have to post the links I've collected of Rails 4 blog posts and commits to the Rails 4 MindNode post so keep checking it.
Rails 4 in a MindNode
Posted by santiago.pastorino
on September 20, 2012
I'll be talking at [RubyConf Argentina](http://rubyconfargentina.org/en),
and the first thing I usually do when preparing talks is to think in a
high level and then start going down form there. I find MindNode a great
tool for that. So I started checking what was being added, removed and
deprecated in Rails 4 (my memory isn't good enough to have all that in the
top of my head :P). The result is this MindNode I'm sharing with you …
[](/images/posts/Rails4-4.png)
I could be missing some stuff or could even be things that won't make it to
Rails 4, but that's the picture as of today. If you find something that I'm
missing or that I should change please let me know. I will keep this
MindNode updated so keep checking it.
**UPDATE #1**: [Support for specifying transaction isolation
level](https://github.com/rails/rails/commit/392eeecc11a291e406db927a18b75f41b2658253)
**UPDATE #2**: [Turbolinks](https://github.com/rails/turbolinks/)
Ruby Refinements landed in trunk
Posted by santiago.pastorino
on August 03, 2012
Refinements arrived to Ruby trunk [here](https://bugs.ruby-lang.org/issues/4085.) The purpose of Refinements is to make monkey patching safer, extending core classes but limiting its effects to a particular area of code.
Shugo Maeda wrote ...
"Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum."
You can read the long story here [https://bugs.ruby-lang.org/issues/4085](https://bugs.ruby-lang.org/issues/4085)
So let's see how Refinements work in practice
Basically instead of doing …
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
puts "".blank?
puts "hi".blank?
puts nil.blank?
puts [].blank?
puts [1].blank?
and polluting all the objects, you can do ...
module Blank
refine Object do
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
end
class A
using Blank
puts "".blank? # => true
puts "hi".blank? # => false
puts nil.blank? # => true
puts [].blank? # => true
puts [1].blank? # => false
end
and monkey patch in a controlled way. You can also check that you won't be polluting all the objects in your system by checking …
class B
puts "".blank?
puts "hi".blank?
puts nil.blank?
puts [].blank?
puts [1].blank?
end
This will raise an undefined method `blank?' for [](String) (NoMethodError).
Refinements has been committed to ruby by Shugo Maeda, but it may be reverted for Ruby 2.0. The Ruby Core is asking for feedback, so, what are the use cases you see Refinements is good for you?
You can learn more about Refinements reading [Refinements in practice, a blog post from Yehuda Katz](http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice/)
Rails for API applications (rails-api) released
Posted by santiago.pastorino
on April 20, 2012
**[rails-api](https://github.com/spastorino/rails-api)** is a plugin developed by Yehuda Katz, José Valim, Carlos Antonio da Silva and me (Santiago Pastorino) which modifies Rails applications trimming down usually unneeded Rails functionalities for API applications.
Do you remember we added support for this on core and [it was reverted](https://github.com/rails/rails/commit/6db930cb5bbff9ad824590b5844e04768de240b1)?. This plugin enables that again.
### What is an API app?
Traditionally, when people said that they used Rails as an "API", they meant providing a programmatically accessible API alongside their web application. For example, GitHub provides [an API](http://developer.github.com/) that you can use from your own API clients.
### Why using this instead of Rails?
Because you don't need the entire Rails middleware stack. Specifically you won't need middleware that are meant for browser applications. For example you probably won't need cookies support, but you can add that back if you want. You don't need most of the functionality provided by ActionController::Base like template generation for instance. And you won't need generated views, helpers and assets. The plugin also skips the asset pipelining.
### Configuration
#### For existing Rails applications you need …
1. To add gem 'rails-api' to your Gemfile
2. Make *ApplicationController* inherit from *ActionController::API* instead of *ActionController::Base*. As with middleware, this will leave out any *ActionController* module that provides functionality primarily used by browser applications.
3. Remove respond_to from your controllers and just use render :json instead.
#### For new apps
Install the gem if you haven't already:
gem install rails-api
Then generate a new **Rails API** application:
rails-api new my_api
And that's it, when you use the generators by default controllers will respond to json only.
### Middlewares
An api application comes with the following middlewares by default.
* *Rack::Cache*: Caches responses with public *Cache-Control* headers using HTTP caching semantics.
* *Rack::Sendfile*: Uses a front-end server's file serving support from your Rails application.
* *Rack::Lock*: If your application is not marked as threadsafe (`config.threadsafe!`), this middleware will add a mutex around your requests.
* *ActionDispatch::RequestId*
* *Rails::Rack::Logger*
* *Rack::Runtime*: Adds a header to the response listing the total runtime of the request.
* *ActionDispatch::ShowExceptions*: Rescue exceptions and re-dispatch them to an exception handling application.
* *ActionDispatch::DebugExceptions*: Log exceptions.
* *ActionDispatch::RemoteIp*: Protect against IP spoofing attacks.
* *ActionDispatch::Reloader*: In development mode, support code reloading.
* *ActionDispatch::ParamsParser*: Parse XML, YAML and JSON parameters when the request's *Content-Type* is one of those.
* *ActionDispatch::Head*: Dispatch *HEAD* requests as *GET* requests, and return only the status code and headers.
* *Rack::ConditionalGet*: Supports the `stale?` feature in Rails controllers.
* *Rack::ETag*: Automatically set an *ETag* on all string responses. This means that if the same response is returned from a controller for the same URL, the server will return a *304 Not Modified*, even if no additional caching steps are taken. This is primarily a client-side optimization; it reduces bandwidth costs but not server processing time.
Other plugins, including *ActiveRecord*, may add additional middlewares. In general, these middlewares are agnostic to the type of app you are building, and make sense in an API-only Rails application.
You can get a list of all middlewares in your application via:
rake middleware
#### Other Middlewares
Rails ships with a number of other middlewares that you might want to use in an API app, especially if one of your API clients is the browser:
* *Rack::MethodOverride*: Allows the use of the *_method* hack to route POST requests to other verbs.
* *ActionDispatch::Cookies*: Supports the *cookie* method in *ActionController*, including support for signed and encrypted cookies.
* *ActionDispatch::Flash*: Supports the *flash* mechanism in *ActionController*.
* *ActionDispatch::BestStandards*: Tells Internet Explorer to use the most standards-compliant available renderer. In production mode, if ChromeFrame is available, use ChromeFrame.
* Session Management: If a *config.session_store* is supplied, this middleware makes the session available as the *session* method in *ActionController*.
Any of these middlewares can be added via:
config.middleware.use Rack::MethodOverride
#### Removing Middlewares
If you don't want to use a middleware that is included by default in the api middleware set, you can remove it using *config.middleware.delete*:
config.middleware.delete ::Rack::Sendfile
Keep in mind that removing these features may remove support for certain features in *ActionController*.
### Choosing Controller Modules
An api application (using *ActionController::API*) comes with the following controller modules by default:
* *ActionController::UrlFor*: Makes *url_for* and friends available
* *ActionController::Redirecting*: Support for *redirect_to*
* *ActionController::Rendering*: Basic support for rendering
* *ActionController::Renderers::All*: Support for *render :json* and friends
* *ActionController::ConditionalGet*: Support for *stale?*
* *ActionController::ForceSSL*: Support for *force_ssl*
* *ActionController::RackDelegation*: Support for the *request* and *response* methods returning *ActionDispatch::Request* and *ActionDispatch::Response* objects.
* *ActionController::DataStreaming*: Support for *send_file* and *send_data*
* *AbstractController::Callbacks*: Support for *before_filter* and friends
* *ActionController::Instrumentation*: Support for the instrumentation hooks defined by *ActionController* (see [the source](https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/instrumentation.rb) for more).
* *ActionController::Rescue*: Support for *rescue_from*.
Other plugins may add additional modules. You can get a list of all modules included into *ActionController::API* in the rails console:
ActionController::API.ancestors - ActionController::Metal.ancestors
#### Adding Other Modules
All Action Controller modules know about their dependent modules, so you can feel free to include any modules into your controllers, and all dependencies will be included and set up as well.
Some common modules you might want to add:
* *AbstractController::Translation*: Support for the *l* and *t* localization and translation methods. These delegate to *I18n.translate* and *I18n.localize*.
* *ActionController::HTTPAuthentication::Basic* (or *Digest* or *Token*): Support for basic, digest or token HTTP authentication.
* *AbstractController::Layouts*: Support for layouts when rendering.
* *ActionController::MimeResponds*: Support for content negotiation (*respond_to*, *respond_with*).
* *ActionController::Cookies*: Support for *cookies*, which includes support for signed and encrypted cookies. This requires the cookie middleware.
The best place to add a module is in your *ApplicationController*. You can also add modules to individual controllers.
### How can I help?
Go to the project url [https://github.com/spastorino/rails-api](https://github.com/spastorino/rails-api) and report issues, test it in real apps and provide bug fixes. We have been measuring the plugin against some applications and we will post more about the results later. Meanwhile, if you can test it and share the improvements you found in your apps, would be awesome. To be able to add this functionality to core we need the plugin to show significant performance improvements for real API applications, so it's important to let us know about your results.
<3 <3 <3 Find me at RailsConf. Tenderlove and I are giving out hugs for free!
**Update #1**: Wycats who after working with us (South American rubyists) is known as wygatos (figure our why :P), is adhering to the campaign of giving hugs for free.
My OS X Rails installation using Homebrew and rbenv, step by step
Posted by sebastian.martinez
on April 13, 2012
In this opportunity I'll explain (as the title suggests) how to go from a brand new mac os x to running Rails tests.
Step 0, is to make sure that
locale returns LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL=
(you'll get some unexpected errors later on if not). To do so, you can either set the Language to one that Mac OS X sets UTF-8 by default, like United States from the System Preferences panel.
Or, you can run
$ export LC_ALL=en_US.UTF-8
$ export LANG=en_US.UTF-8
to achieve that.
Step 1, install Xcode.
Step 2, install osx-gcc-installer from https://github.com/kennethreitz/osx-gcc-installer
Step 3, So now you're ready to install Homebrew, by doing:
$ /usr/bin/ruby -e "$(/usr/bin/curl -fksSL https://raw.github.com/mxcl/homebrew/go)"
Now this is how to install some common libraries
Step 4, We need to first have git in order run the brew doctor, so
$ brew install git
You can make sure that everything is ok by running $ brew doctor at any time. It should return 'Your system is raring to brew' when in optimal conditions.
Step 5, now to install the rest of the libraries
$ brew install memcached mysql postgresql
Step 6, initializing the mysql and postgres databases must be done by doing
$ initdb /usr/local/var/postgres
$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew
--prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp
Step 7, I like having some aliases to load/unload mysql, postgres and memcached. To do so, you should add the following lines to your ~/.zshrc
alias memcached_load="launchctl load -w /usr/local/Cellar/memcached/1.4.13/homebrew.mxcl.memcached.plist"
alias memcached_unload="launchctl unload -w /usr/local/Cellar/memcached/1.4.13/homebrew.mxcl.memcached.plist"
alias mysql_load="launchctl load -w /usr/local/Cellar/mysql/5.5.20/homebrew.mxcl.mysql.plist"
alias mysql_unload="launchctl unload -w /usr/local/Cellar/mysql/5.5.20/homebrew.mxcl.mysql.plist"
alias postgres_load="launchctl load -w /usr/local/Cellar/postgresql/9.1.3/homebrew.mxcl.postgresql.plist"
alias postgres_unload="launchctl unload -w /usr/local/Cellar/postgresql/9.1.3/homebrew.mxcl.postgresql.plist"
Step 8, Now you're good to go. Next we'll install rbenv to easily switch between multiple versions of Ruby. You can also choose to use RVM or roll your own.
$ brew install rbenv ruby-build
Step 9, Add
export PATH=$HOME/.rbenv/bin:$PATH
eval "$(rbenv init -)"
to your ~/.zshrc.
Step 10, now do the following to install ruby $ rbenv install 1.9.3-p125
Step 11, you need to $ rbenv global 1.9.3-p125
$ rbenv rehash
Step 12, Cool, so now we are good to go and setup Rails.
$ git clone https://github.com/rails/rails.git
$ gem install bundler
$ rbenv rehash
$ cd rails
$ bundle
Step 13, now, from the Contributing to Rails Guide, you should
$ mysql_load
$ postgres_load
$ mysql -u root
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.* to 'rails'@'localhost';
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.* to 'rails'@'localhost';
exit
$ cd activerecord
$ rake mysql:build_databases
$ rake postgresql:build_databases
And that's it!, we have Ruby, MySQL, PostgreSQL, Memcached, and everything needed to do some Rails development.
Step 14, we need to load Memcached for its needed for some tests by doing
$ memcached_load
Step 15, and lastly, you can run Rails tests by doing
$ rake
at the top of the rails directory.
Everything should work just fine, or at least you should get the same results as the [Rails CI.](http://travis-ci.org/#!/rails/rails)
Congratulations!
bundle exec rails … executes Bundler.setup 3 times
Posted by santiago.pastorino
on December 27, 2011
*TL;DR*: don't run *bundle exec* before *rails* command, rails already checks the presence of *Bundler* through the *Gemfile* and sets up everything according to it without the overhead of *bundle exec_. _rails* command is the only exception to the rule. Additionally I've added a [patch](https://github.com/carlhuda/bundler/commit/2c838255ccadadeab5298b7c2bbc39035e59f248) to *Bundler* that avoids calling Bundler.setup which adds unnecessary overhead.
I was researching on a huge *Bundler 1.1* performance regression, [@masterkain](http://twitter.com/masterkain) was hitting when running *bundle exec rails runner ''* (you shouldn't run bundle exec before the *rails* command, but keep reading for now). I started to profile it using *ruby-prof* and one of the things I realized was that *Bundler.setup* (which is a considerable slow method because it calls [Bundler::Runtime#setup](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler/runtime.rb#L7-42)) was ran 3 times. My first reaction was WTF?? 3 times??. I will write about my other findings in another blog post.
After analyzing the code, I found out that the first call to *Bundle.setup* is in [Bundler::CLI#exec](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler/cli.rb#L398) right before shelling out to run _rails runner ''_.
The second call is on [boot.rb](https://github.com/rails/rails/blob/d2abe28ed342443f8c374a6e02977ccb0c3b3f95/railties/lib/rails/generators/rails/app/templates/config/boot.rb#L6) as part of the boot process (well actually it's required from *bundle exec* through [this rubyopt](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler/runtime.rb#L227) and on boot.rb the require returns false because it's already required).
And the last call starts on [config/application.rb](https://github.com/rails/rails/blob/d2abe28ed342443f8c374a6e02977ccb0c3b3f95/railties/lib/rails/generators/rails/app/templates/config/application.rb#L17)
which ends up calling [Bundler.require](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler.rb#L120-122) to finally call *Bundler.setup* for the third time.
The second and third calls are run on the same process so *Bundler.setup* caches the result in [@setup](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler.rb#L105) so there's no slow down between those 2 calls.
But the command passed to *bundle exec* runs in a different process (remember I said before that we were shelling out to run *rails runner ''_) so the resulting execution of the first _Bundler.setup* won't be available to the [rails runner process" and doesn't make any sense. All that *bundle exec* needs to do is to "setup the rubyopts](https://github.com/carlhuda/bundler/blob/2a38a24a295b6e978f0c982d454a3a9f11399abc/lib/bundler/runtime.rb#L209-231) needed to run the command you are passing to *bundle exec_. I've [patched](https://github.com/carlhuda/bundler/commit/2c838255ccadadeab5298b7c2bbc39035e59f248) _Bundler* to do the right thing.
So don't run *bundle exec* before *rails* command, this command is already aware of *Bundler* and sets up everything according to what you have on your _Gemfile_.
If you prepend *bundle exec* before *rails* command all you will be adding is overhead of opening another process from *Bundler* and executing useless code since *rails* already does the right thing.
You probably already know about that, but I've seen a lot of proficient Rails developers doing it.
Read more about the topic in [Yehuda's blog](http://yehudakatz.com/2011/05/30/gem-versioning-and-bundler-doing-it-right/)
Ruby 1.9.3 and ruby-debug
Posted by santiago.pastorino
on November 01, 2011
As you probably know Ruby (MRI so brixen doesn't get mad at me :P) [1.9.3 was released](http://www.ruby-lang.org/en/news/2011/10/31/ruby-1-9-3-p0-is-released/.) I've been using 1.9.3 for a while now and as part of my RubyConf Uruguay talk I wanted to show ruby-debug. So my first attempt was:
$ gem install ruby-debug19
Fetching: linecache19-0.5.12.gem (100%)
Building native extensions. This could take a while...
Fetching: ruby-debug-base19-0.11.25.gem (100%)
Building native extensions. This could take a while...
Fetching: ruby-debug19-0.11.6.gem (100%)
Successfully installed linecache19-0.5.12
Successfully installed ruby-debug-base19-0.11.25
Successfully installed ruby-debug19-0.11.6
3 gems installed
Then require 'ruby-debug' and booom!!
$ irb
irb(main):001:0> require 'ruby-debug'
LoadError: dlopen(/Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle, 9): Symbol not found: _ruby_current_thread
Referenced from: /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle
Expected in: flat namespace
in /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle - /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug-base19-0.11.25/lib/ruby-debug-base.rb:1:in `'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/gems/1.9.1/gems/ruby-debug19-0.11.6/cli/ruby-debug.rb:5:in `'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:59:in `require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:59:in `rescue in require'
from /Users/santiago/.rbenv/versions/1.9.3/lib/ruby/1.9.1/rubygems/custom_require.rb:35:in `require'
from (irb):1
from /Users/santiago/.rbenv/versions/1.9.3/bin/irb:12:in `'
So after some research on the internet I found out that the author of ruby-debug had a fix for it which he considered unstable and didn't push it to rubygems.org yet. Since I prefer an unstable ruby-debug than a non working one :P, I gave it a try ...
First download linecache19-0.5.13.gem and ruby-debug-base19-0.11.26.gem from [http://rubyforge.org/frs/?group_id=8883](http://rubyforge.org/frs/?group_id=8883), then …
$ gem install linecache19-0.5.13.gem
Building native extensions. This could take a while...
Successfully installed linecache19-0.5.13
1 gem installed
$ gem install ruby-debug-base19-0.11.26.gem -- --with-ruby-include=/Users/santiago/.rbenv/source/ruby-1.9.3-p0
Building native extensions. This could take a while...
Successfully installed ruby-debug-base19-0.11.26
1 gem installed
$ irb
irb(main):001:0> require 'ruby-debug'
=> true
and voilá.
So while we wait for an official release, you can enjoy a working ruby-debug.
RailsConf 2010: Interview with Caike Souza
Posted by jose.costa
on March 25, 2011
We're opening the box of RailsConf 2010 memories! Yep ... we suck at journalism, so it turns out we have this almost one year old interview with Caike Souza we never shared before. So sorry Caike!
Caike ([@caike](http://twitter.com/caike)) is a passionate agile software craftsman and founder of the [Orlando Code Dojo](http://orlandodojo.org/) group, where programmers get together to practice coding to improve their skills once a month. He is currently working at [Envy Labs](http://envylabs.com/.)
Thanks for your time and great vibe!
Metaprogramming in Ruby slides from my talk at RubyConf Uruguay
Posted by santiago.pastorino
on November 04, 2010
Metaprogramming
View more presentations from Santiago Pastorino.
RailsConf 2010: Interview with George Guimarães
Posted by jose.costa
on July 28, 2010
Among the great people we met at the RailsConf was George Guimarães ([@georgeguimaraes](http://twitter.com/georgeguimaraes)), by no surprise he was a very cool and funny dude, and he was open to talk and hang around with us.
George is co-founder of [Plataforma Tec](http://plataformatec.com.br/), that many of us got to know well through their amazing set of gems/plugins and the stunning work José Vailm has been doing as a Rails Core team member. Kind of what I hope it's happening with the great work Santiago Pastorino is doing with his contributions and how it's reinforcing WyeWorks reputation.
But still there are a lot of guys behind the scenes that support this great Open Source effort that's being carried in these companies, probably not so much by direct intervention but with more hard and 'real' work as we like to say to joke around and bother the OSS guys. The kind of work that pay the bills :P
Not that George doesn't do OSS, actually he's currently involved in the development of [Restfulie](http://github.com/caelum/restfulie) that got many people pretty excited at the RailsConf this year, and much more stuff.
Hope you enjoy this not so serious take.
Thanks George!
RailsConf 2010: Interview with Fabio Akita
Posted by jose.costa
on July 01, 2010
In the last day of the RailsConf 2010 Santiago and I got the pleasure to hang out a few hours with Fabio Akita, a very successful guy in the Ruby and Rails community, but yet so humble and open as many of the great people we met in these past days.
Fabio is well known as a great evangelist of this movement, as a great speaker, for his bundle of plugins for the vim editor but also for carrying interviews with important people of the community on every conference he attends. The thing is that personally I never got to see him as the subject of the interview, and he is a wise guy that has a lot to say. So even though he was very tired, he accepted to do this improvised short interview with me, almost the first time I was holding a camera.
This is the first of a small series of interviews that will be posted soon.
I hope you all enjoy it and share his thoughts on what are the good things that makes this community so special, so that we never loose that spirit.
Thanks Fabio!
4 Ways to Retrieve a Twitter List Timeline
Posted by santiago.pastorino
on February 01, 2010
For past few days we had been working on the new version of the WyeWorks site, so stay tunned.
This new version will have a twitter section, where the last 5 tweets of our team will be displayed.
So first thing I had to do was installing the twitter gem:
gem install twitter
In order to achieve this, I've found 3 different ways using the twitter gem, plus one not yet implemented on the gem, that I've already proposed the patch.
The dumbest one would be:
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
users = %w(wyeworks spastorino joseicosta smartinez87 nartub)
tweets = users.map { |user_name| Twitter::Search.new.from(user_name) }.
inject([]) { |tweets, search| tweets + search.fetch(5).results }.
sort { |t1, t2| Date.parse(t2.created_at) <=> Date.parse(t1.created_at) }[0,5]
tweets.each do |tweet|
puts tweet.created_at
puts tweet.from_user
puts tweet.profile_image_url
puts tweet.text
end
What this does is retrieve the last 5 tweets of each user and merge them sorted by date.
Obviously, best thing to do would be directly retrieving the last 5 tweets from the @wyeworks/team list.
Only way to do this using the gem requires authentication, despite the list being public.
In order to authenticate, we may take two paths, the first one would be using HTTP Authentication:
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
httpauth = Twitter::HTTPAuth.new('wyeworks', 'password')
base = Twitter::Base.new(httpauth)
base.list_timeline('wyeworks', 'team', :page => 1, :per_page => 5).each do |tweet|
puts tweet.created_at
puts tweet.user.screen_name
puts tweet.user.profile_image_url
puts tweet.text
end
The other and preferred way for authentication is OAuth, since we don't have to send the user and password through the network.
In order to make OAuth work with twitter, we have to create an application at [http://twitter.com/apps](http://twitter.com/apps)
Once we've created the app, twitter provides us with a Consumer Key and a Consumer Secret, needed to authenticate using OAuth
#!/usr/bin/env ruby
require 'rubygems'
require 'twitter'
oauth = Twitter::OAuth.new('consumer token', 'consumer secret')
begin
oauth.authorize_from_access(oauth.request_token.token, oauth.request_token.secret)
base = Twitter::Base.new(oauth)
base.list_timeline('wyeworks', 'team', :page => 1, :per_page => 5).each do |tweet|
puts tweet.created_at
puts tweet.user.screen_name
puts tweet.user.profile_image_url
puts tweet.text
end
rescue OAuth::Unauthorized
puts "> FAIL!"
end
Either of these ways works just fine, but no one completely satisfied me, since we are working with a **public** list, so as far as I can see authentication is out the question, even more when anyone can see it directly from the web without authenticating.
For this reason, I started looking at the [Twitter API](http://apiwiki.twitter.com) searching for a non-authentication way to do it: [Here's](http://apiwiki.twitter.com/Twitter-REST-API-Method:-GET-list-statuses) what I found.
You can test that making a request to [http://api.twitter.com/1/wyeworks/lists/team/statuses.json?page=1&per_page=5](http://api.twitter.com/1/wyeworks/lists/team/statuses.json?page=1&per_page=5), obtaining the list as a json, or xml in case you change the .json to .xml
So I've came up with this monkey-patch:
module Twitter
# :per_page = max number of statues to get at once
# :page = which page of tweets you wish to get
def self.list_timeline(list_owner_username, slug, query = {})
response = HTTParty.get("http://api.twitter.com/1/#{list_owner_username}/lists/#{slug}/statuses.json", :query => query, :format => :json)
response.map{|tweet| Hashie::Mash.new tweet}
end
end
Being able to get the list without authenticating by:
Twitter.list_timeline('wyeworks', 'team', :page => 1, :per_page => 5).each do |tweet|
puts tweet.created_at
puts tweet.user.screen_name
puts tweet.user.profile_image_url
puts tweet.text
end
I've already contacted the gem's authors, proposing this patch: [http://github.com/spastorino/twitter/commit/aed3a298b613a508bb9caf93afc7f12c50626ad7](http://github.com/spastorino/twitter/commit/aed3a298b613a508bb9caf93afc7f12c50626ad7.) Wynn Netherland already told me it's pretty probable that it will be approved.
Until then, you can make use of this functionality from my fork [http://twitter.com/spastorino/twitter](http://twitter.com/spastorino/twitter)
**UPDATE #1:** My fork was merged into [http://github.com/jnunemaker/twitter](http://github.com/jnunemaker/twitter) master branch and twitter 0.8.3 was published through [Gemcutter](http://gemcutter.org/gems/twitter)
Generating PDF with odf-report and images support
Posted by jose.costa
on September 18, 2009
Well i guess many of you might have checked the last edition of the [Rails Magazine](http://railsmagazine.com/issues/4.) If not, you may should.
In particular one of the articles by Rodrigo Rosenfeld Rosas talks about PDF generation with odf templates, something I've been playing around in the last few weeks.
He explains the mechanism that can be used for this purpose and finally mentions the **odf-report** gem by Sandro Duarte which i've been using and forked to add support for image substitutions.
*More info here*: [http://github.com/josecosta/odf-report](http://github.com/josecosta/odf-report)
Give it a try!
**UPDATE**
Fork was merged to [master branch](http://github.com/sandrods/odf-report.)
My Emacs for Rails
Posted by santiago.pastorino
on September 11, 2009
I'd like to share with the community my emacs init file and a set of plugins to give a nicer experience on Ruby on Rails development, which you can checkout from http://github.com/spastorino/my_emacs_for_rails/tree/master.
I have been using this environment under emacs 23, and it has not been tested on other emacs versions, so all feedback is welcome, if something goes wrong please feel free to contact me.
## What's in the package?
The package provides my customized Emacs init file and some plugins I found very useful to enhance Ruby on Rails development experience.
### Plugins
* anything
* auto-complete
* autotest
* [cedet](http://cedet.sourceforge.net/)
* color-theme
* [ecb](http://ecb.sourceforge.net/)
* find-recursive
* flymake
* javascript
* [nxhtml](http://ourcomments.org/Emacs/nXhtml/doc/nxhtml.html)
* [rcodetools](http://eigenclass.org/hiki.rb?rcodetools)
* rdebug
* redo
* ri-emacs
* [rinari](http://rinari.rubyforge.org/)
* ruby-block
* ruby-mode
* toggle
* yaml-mode
* [yasnippet](http://code.google.com/p/yasnippet/)
* [yasnippets-rails](http://github.com/eschulte/yasnippets-rails/tree/master)
## Installation
Before you can use some plugins you have to install a few packages:
To use rcodetools you need to install the rcodetools, gem with
sudo gem install rcodetools
To use autotest you need the ZenTest gem, install it with
sudo gem install ZenTest
On further post I'm going to explain how to set it up under the gnome environment using all the beauty that gnome-notifier has.
Checkout the package
git clone github.com/spastorino/my_emacs_for_rails
and copy all the files under my_emacs_for_rails directory to ~/.emacs.d directory if it doesn't exist you have to create it.
## Screenshot
You can see here some screenshots to get a taste of the look and feel that this one has.
!http://blog.wyeworks.com/assets/2009/9/11/emacs-screenshot.png!:http://blog.wyeworks.com/assets/2009/9/11/emacs-screenshot-full.png
Method missing to simplify queries to an external service
Posted by jose.costa
on August 05, 2009
I know there are several discussions on the usage of method_missing in Ruby.
In this post i'll present a pretty simple, yet useful solution that uses method_missing to interact with the [Brightcove Media Read API(Getting Started with the Media API)](http://support.brightcove.com/en/docs/getting-started-media-api) (you don't need to be familiar with this service, i'll explain a little bit in the next few lines).
[Brightcove Media Read API(Getting Started with the Media API)](http://support.brightcove.com/en/docs/getting-started-media-api) accepts calls of the form:
http://api.brightcove.com/services/library?command=find_all_videos
&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.
http://api.brightcove.com/services/library?command=find_related_videos
&video_id=123123&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.
http://api.brightcove.com/services/library?command=find_videos_by_text
&text=sometextsample&pageSize=100&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.
A token must be passed on each call, and you could also add more parameters like you would do in a regular GET request.
What comes back is a JSON string that can be easily picked up.
The key thing here is to notice that there are several commands you could execute from the [API](http://docs.brightcove.com/en/media/#Video_Read), naturally each with its own name that must be specified in the request right after [command=". Since the "API](http://docs.brightcove.com/en/media/#Video_Read) also provides a set of error codes to address all wrong requests or non-existent commands requests, we simply wanted to forward all the calls to the [API](http://docs.brightcove.com/en/media/#Video_Read) and reply back with its answer. So, in order to avoid defining all [API](http://docs.brightcove.com/en/media/#Video_Read) methods in our Ruby module, we just used the method_missing and forwarded all calls to it, using the name of the method as the [API](http://docs.brightcove.com/en/media/#Video_Read) command.
The idea was that a call like:
http://api.brightcove.com/services/library?command=find_videos_by_user_id
&user_id=34876423&token=0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.
became just:
Brightcove::ReadProxy.find_videos_by_user_id :user_id => 34876423
We then implemented what we called the Brightcove::ReadProxy in a few lines like shown below:
module Brightcove
module ReadProxy
TOKEN = '0Z2dtxTdJAxtbZ-d0U7Bhio2V1Rhr5Iafl5FFtDPY8E.'
SITE = 'http://api.brightcove.com/services/library'
def self.method_missing(method_id, *args)
args[0] ||= { }
args[0].merge!({ :command => method_id, :token => TOKEN })
get SITE, args[0]
end
def self.get(url, params)
http_client = HTTPClient.new
result = http_client.get(url, params)
content = nil
begin
content = JSON.parse(result.content)
rescue Exception => e
Rails.logger.error e.message
end
return content
end
end
Basically all the magic relies in the method_missing that would convert any call to the Brightcove::ReadProxy module in the format accepted by the [API](http://docs.brightcove.com/en/media/#Video_Read), without having to define every [API](http://docs.brightcove.com/en/media/#Video_Read) method and maintaining the Rails like finders syntax.
We also used the httpclient gem to simplify the GET request calls and the json gem to parse the result of the call.
I'm not saying that this is the best usage, but i think in this particular situation it suits pretty well.
What do you think?
Drag & Drop Sortable Lists
Posted by sebastian.martinez
on July 27, 2009
Time has come for us to make a sortable list, and let's face it, drag&drop are the prettiest ones. So, let me explain how to proceed.
Suppose you have a playlist with many videos, and want to establish an order on which they will be played. First thing you will need is to add a 'position' attribute to your Video model. To do that, we'll generate a migration first:
script/generate migration add_position_to_videos position:integer
Now just run *rake db:migrate*.
View Code
First thing you need to make sure, is that you have the prototype and scriptaculous libraries in your application. Now let's see how your **index.html.erb** file should look like Videos
<% @videos.each do |video| %>
<% content_tag_for :li, video do %>
<%= link_to video.name, video_path(video) %>
<% end %>
<% end %>
<%= link_to "New Video, new_video_path %>
Now all we have to do to make the list sortable is add the sortable_element helper method to the index view. You need to pass it the id of the element you want to be sortable, and a URL that is called via an AJAX request so that the updated positions can be stored in the database.
<%= sortable_element('videos', :url => 'sort_videos_path') %>
The videos in the list can now be dragged and dropped, but the new order isn’t persisted back to the database.
So let's code the sort method in the videos_controller.rb
def sort
params[:videos].each_with_index do |id, index|
Video.update_all([’position=?’, index+1], [’id=?’, id])
end
render :nothing => true
end
And that's it. We are now updating the position of the videos.
Most probably, we would want now our videos to be shown in the index in the correct order, so we just need to touch the index method on the controller a bit.
def index
@videos = Video.all(:order => ’position’)
end
At this point we are almost set to go...did you guess what's missing? Yes, we need to add the route to the sort method :)
map.resources :videos, :collection => { :sort => :post}
The line above adds the new action and makes it a POST request, which is the type that our AJAX call uses when making XMLHTTP requests.
And that's pretty much it. Now you have a fully functional sortable list of videos.
There are some more tricks we can use to improve this, for example, the **sortable_element** helper receives one option called 'handle'. What's this? The way to specify the draggable area of the element. This I think is the most used one. Let's give it a try:
We should first add a span tag on the index view:
<% content_tag_for :li, video do %>
[drag]
<%= link_to video.name, video_path(video) %>
<% end %>
Note the span has a 'handle' class, and that's what you are going to set as draggable, using the :handle option:
<%= sortable_element(’videos’), :url => sort_videos_path, :handle => ’handle’ %>
You can style this a bit with a CSS, adding a line similar to this one:
li .handle { color: #777; cursor: move; font-size: 12px; }
Beautiful....just beautiful...
Ok, we have this magical sortable list now, but we added a 'position' field to videos...we can handle this manually when creating or updating the videos, or we can use the **acts_as_list** plugin, which I recommend.
Just install it by typing script/plugin install git://github.com/rails/acts_as_list.git in your console.
All configuration this needs to work is to add **acts_as_list** in our model, that should look like this:
class Video < ActiveRecord::Base
acts_as_list
end
Congrats!!! Enjoy your sortable list !!!
RVideo for video processing and inspection
Posted by jose.costa
on July 20, 2009
At WyeWorks headquarters, every once in a while, we come across some project that needs a media edition/transcoding solution to build into. This was the case of our latest project in which we built a pretty simple interface with [Brightcove(Brightcove - The Leading Online Video Platform.)](http://www.brightcove.com/), a powerful video platform on which we may write something about it in our forthcoming posts, but it's not the point right now.
Turns out to be that Brightcove recommends that files should be encoded using either H.264 or VP6. As usual, we ask ffmpeg for salvation when we need to transcode media files and this was not the exception. But we didn't want to transcode just every file nor make the choice based on the file's extension. We wanted a way to check the current file encoding.
Searches made at that time lead us to think that the usual way to get a media file encoding is by running:
ffmpeg -i
which i must say that it's pretty ugly for me since that command it's supposed to be used for conversion and as far as i know it doesn't offer some flag to get only the file information.
In fact, that command returns an error (but still prints the information we need):
jose:~$ ffmpeg -i barsandtone.flv
FFmpeg version 0.5-svn17737+3:0.svn20090303-1ubuntu6, Copyright (c) 2000-2009 Fabrice Bellard, et al.
configuration: --enable-gpl --enable-postproc --enable-swscale --enable-x11grab --extra-version=svn17737+3:0.svn20090303-1ubuntu6 --prefix=/usr --enable-avfilter --enable-avfilter-lavf --enable-libgsm --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-pthreads --disable-stripping --disable-vhook --enable-libdc1394 --disable-armv5te --disable-armv6 --disable-armv6t2 --disable-armvfp --disable-neon --disable-altivec --disable-vis --enable-shared --disable-static
libavutil 49.15. 0 / 49.15. 0
libavcodec 52.20. 0 / 52.20. 0
libavformat 52.31. 0 / 52.31. 0
libavdevice 52. 1. 0 / 52. 1. 0
libavfilter 0. 4. 0 / 0. 4. 0
libswscale 0. 7. 1 / 0. 7. 1
libpostproc 51. 2. 0 / 51. 2. 0
built on Apr 10 2009 23:18:41, gcc: 4.3.3
Input #0, flv, from 'barsandtone.flv':
Duration: 00:00:06.00, start: 0.000000, bitrate: 505 kb/s
Stream #0.0: Video: *vp6f*, yuv420p, 360x288, 409 kb/s, 1k tbr, 1k tbn, 1k tbc
Stream #0.1: Audio: mp3, 44100 Hz, stereo, s16, 96 kb/s
**Must supply at least one output file**
The information we need is the video codec (in this case vp6f) to determine if we need to transcode it.
Another thing to mention is that nothing that you see as the output there outputs to the stdout.
No rocket science needed but i was kind of lazy to parse this from scratch. Lucky for me, there was this not so new [rvideo(rvideo)](http://code.google.com/p/rvideo/) gem (still unknown for me) that made me save some precious time.
[RVideo(rvideo)](http://code.google.com/p/rvideo/) still relies in ffmpeg command and also it's internal work to get the information we need involves that same output parsing, you just don't have to do it yourself.
After installation (not covered here, just check rvideo readme file), you can do things as shown below:
inspector = RVideo::Inspector.new(:file => file.path)
inspector.video_codec
=> "vp6f"
inspector.duration
=> 6000
inspector.audio_codec
=> "mp3"
We've just made a tiny introduction to inspection. I'm not covering video processing. Check [rvideo(rvideo)](http://code.google.com/p/rvideo/) for more details!
Enjoy!
Paperclip file rename
Posted by santiago.pastorino
on July 13, 2009
While developing an application with Sebastián that allow users to upload videos with some file name restrictions, meaning that it must contain only A-Z and 0-9 digits, underscores (_) as a valid component as well, and also the name must be preceded by it's own #id, we came up with the need of applying this custom filter to each uploaded video.
After doing some research on paperclip source code and internet tutorials, we suggest the following solution:
class Video < ActiveRecord::Base
has_attached_file :video,
:path => ":rails_root/public/system/:attachment/:id/:style/:normalized_video_file_name",
:url => "/system/:attachment/:id/:style/:normalized_video_file_name"
Paperclip.interpolates :normalized_video_file_name do |attachment, style|
attachment.instance.normalized_video_file_name
end
def normalized_video_file_name
"#{self.id}-#{self.video_file_name.gsub( /[^a-zA-Z0-9_\.]/, '_')}"
end
end
What are we doing here? Easy, in **has_attached_file** we edit the way paperclip returns the **path** and **url** by default, the most relevant components when saving and loading the file in order to display it.
Paperclip default values are:
path default => ":rails_root/public/system/:attachment/:id/:style/:filename"
url default => "/system/:attachment/:id/:style/:filename"
Values preceded by ':' are the standard interpolations paperclip has. For further information on this visit [http://wiki.github.com/thoughtbot/paperclip/interpolations(Interpolations)](http://wiki.github.com/thoughtbot/paperclip/interpolations.)
What we did was change **:filename** with **:normalized_video_file_name** in both path and url, being the second a custom interpolation and then added the 'normalized_video_file_name' method to video.rb.
By doing this we not only achieve a way for paperclip to handle the file by this normalized way, but also have a method to access the normalized file name, plus being able to access the original file name through paperclip video_file_name method.
So remember on video_file_name you have the uploaded filename and on normalized_video_file_name you have the server filename.
Is your product Innovative?
Posted by martin.alcala
on July 06, 2009
That's a good question, in fact, can we quantify or measure how much "innovation" quantity exists in our product or services?. Well, there are as much answers as successful products ;-) but in general terms we can group Innovation in three categories:
* Business Model
Is your Business Model Innovative? did you find out a new way to sell? did you find out an hidden need of the community? Starbucks would be a nice example.
* Tech
Did you invent new super algorithm to ultra-fast classify all the info on the web ;-) - that a techy innovation -. Tech is a great point for innovation, but not the only one, think about twitter for example.
* Design
Design in fact is key a factor for innovation, for example think about the IPhone or the IPod, the key was the design and the marketing.
So you reader, Rails Enthusiast, Ruby Rockstar, Code Ninja, are you ready to innovate in the wide sense or the word?
Rails delegate method
Posted by sebastian.martinez
on June 04, 2009
Delegation is a feature Rails introduced in it's 2.2 version, and in my opinion are quite useful and somehow something we don't see too much around.
The concept of delegation is to take some methods and send them off to another object to be processed.
Let me explain this with a brief example:
Suppose you have a User class for anyone registered on your site, and a Customer class for those who have actually placed orders:
class User < ActiveRecord::Base
belongs_to :customer
end
class Customer < ActiveRecord::Base
has_one :user
end
As for now, if you are in a Customer instance, you can get their User information doing *@customer.user.name*, or *@customer.user.email*.
Delegation allows you to simplify this:
class User < ActiveRecord::Base
belongs_to :customer
end
class Customer < ActiveRecord::Base
has_one :user
delegate :name, :name=, :email, :email=, :to => :user
end
Now you can refer to **@customer.name** and **@customer.email** to retrieve and set values for those attributes directly. Pretty nice, huh?
We are now working on some code to make possible to inherit behaviour, along with polymorphic associations, so when you create a Cutomer, the User gets created as well with the data you provided when creating the customer, and so on.
So keep posted, for there will be more to come...
Parsing an OPML with Ruby
Posted by sebastian.martinez
on February 20, 2009
And Ruby just doesn't stop surprising us!!
In the past we have to deal with XML files and parse them, incredibly easy task using Hpricot library. Now the turn was for [OPML(OPML)](http://en.wikipedia.org/wiki/OPML) (Outline Processor Markup Language) files. In case you are not familiar with this type of files, its most common use is to exchange lists of web feeds between web feed aggregators.
We found this function to parse the OPML document recursively preserving its structure in the [desktop weblog(desktop weblog)](http://dekstop.de/weblog/), that does the job of extracting the feeds, and modified it a bit. Now it returns a hash containing the title of the articles as keys, and its links as values.
Here's the function:
def self.parse_opml(opml_node, parent_names=[])
feeds = {}
opml_node.elements.each('outline') do |el|
if (el.elements.size != 0)
feeds.merge!(parse_opml(el, parent_names + [el.attributes['text']]))
end
if (el.attributes['xmlUrl'])
feeds[el.attributes['title']] = el.attributes['xmlUrl']
end
end
return feeds
end
All you have to do is call it this way:
require 'rexml/Document'
opml = REXML::Document.new(File.read('my_feeds.opml'))
feeds = parse_opml(opml.elements['opml/body'])
Pretty easy, huh? Try it out and leave your comments...
Twenty Reasons I Love Ruby
Posted by sebastian.martinez
on January 23, 2009
Inspired by Hal Fulton's article [Thirty-seven Reasons I Love Ruby(Thirty-seven Reasons I Love Ruby)](http://rubyhacker.com/ruby37.html), i'd like to share my top twenty reasons I love Ruby.
1. **{color:#993300}It's object-oriented.** What does that mean? Well, for every ten programmers, there are twelve opinions as to what OOP is. I will leave it your judgment. But for the record, Ruby does offer encapsulation of data and methods within objects and allows inheritance from one class to another; and it allows polymorphism of objects. Unlike some languages (like C++ for instance) Ruby was designed from the beginning to be object-oriented.
1. **{color:#993300}It's a pure OOP language.** Am I being redundant? I don't think so. By this I mean that everything, including primitive data types such as strings and integers, is represented as an object. There is no need for wrapper classes such as Java has. And in addition, even constants are treated as objects, so that a method may be invoked with, for example, a numeric constant as a receiver.
1. **{color:#993300}It's a dynamic language.** For people only familiar with more static languages such as C++ and Java, this is a significant conceptual leap. It means that methods and variables may be added and redefined at runtime. It obviates the need for such features as C's conditional compilation (*#ifdef*), and makes possible a sophisticated reflection API. This in turn allows programs to become more "self-aware" -- enabling runtime type information, detection of missing methods, hooks for detecting added methods, and so on.
1. **{color:#993300}It's an interpreted language.** This is a complex issue, and deserves several comments. It can be argued that performance issues make this a negative rather than a positive. To this concern, I reply saying that a rapid development cycle is a great benefit, and it is encouraged by the interpreted nature of Ruby.
1. **{color:#993300}It understands regular expressions.** For years, this was considered the domain of UNIX weenies wielding clumsy tools such as **grep** and *sed*, or doing fancy search-and-replace operations in *vi*. Perl helped change that, and now Ruby is helping, too. More people than ever recognize the incredible power in the super-advanced string and text manipulation techniques.
1. **{color:#993300}It's multi-platform.** It runs on Linux and other UNIX variants, the various Windows platforms, BeOS, and even MS-DOS.
1. **{color:#993300}It's derivative.** Is this a good thing? Outside of the literary world, yes, it is. Isaac Newton said, "If I have seen farther than others, it is because I stood on the shoulders of giants." Ruby certainly has stood on the shoulders of giants. It borrows features from Smalltalk, CLU, Lisp, C, C++, Perl, Kornshell, and others. The principles I see at work are: 1. Don't reinvent the wheel. 2. Don't fix what isn't broken. 3. Finally, and especially: Leverage people's existing knowledge. You understand files and pipes in UNIX? Fine, you can use that knowledge. You spent two years learning all the **printf** specifiers? Don't worry, you can still use *printf*. You know Perl's regex handling? Good, then you've walked a way in Ruby path too.
1. **{color:#993300}It has a smart garbage collector.** Routines like **malloc** and **free** are only last night's bad dream. You don't even have to call destructors. Enough said.
1. **{color:#993300}It's a scripting language.** Don't make the mistake of thinking it isn't powerful because of this. It's not a toy. It's a full-fledged language that happens to make it easy to do traditional scripting operations like running external programs, examining system resources, using pipes, capturing output, and so on.
1. **{color:#993300}It's open-source.** You want to look at the source code? Go ahead. Want to suggest a patch? Go ahead. You want to connect with a knowledgeable and helpful user community, including the language creator himself? You can. Welcome on board.
1. **{color:#993300}It has an advanced Array class.** Arrays are dynamic; you don't have to declare their size at compile-time as in, say, Pascal. You don't have to allocate memory for them as in C, C++, or Java. They're objects, so you don't have to keep up with their length; it's virtually impossible to "walk off the end" of an array as you might in C. Want to process them by index? By element? Process them backwards? Print them? There are methods for all these. Want to use an array as a set, a stack, or a queue? There are methods for these operations, too. Want to use an array as a lookup table? That's a trick question; you don't have to, since we have hashes for that.
1. **{color:#993300}It's extensible.** You can write external libraries in Ruby or in C. In addition, you can modify the existing classes and objects at will, on the fly.
1. **{color:#993300}It uses punctuation and capitalization creatively.** A method returning a Boolean result (though Ruby doesn't call it that) is typically ended with a question mark, and the more destructive, data-modifying methods are named with an exclamation point. Simple, informative, and intuitive. All constants, including class names, start with capital letters. All object attributes start with an @ sign. Again, simple.
1. **{color:#993300}It pays attention to detail.** Synonyms and aliases abound. You can't remember whether to say **size** or **length** for a string or an array? Either one works. For ranges, is it **begin** and **end*, or *first** and *last*? Take your pick. You spell it *indices*, and your evil twin spells it *indexes*? They both work.
1. **{color:#993300}It has a debugger.** In a perfect world, we wouldn't need debuggers. This is not a perfect world.
1. **{color:#993300}It is concise.** There are no superfluous keywords such as Pascal's **begin*, *then** after **if*, *do** after *while*. Variables need not be declared, as they do not have types. Return types need not be specified for methods. The return keyword is not needed; a method will return the last evaluated expression. On the other hand... it is not so cryptic as C.
1. **{color:#993300}It is expression-oriented.** You can easily say things like *x = if a < 0*.
1. **{color:#993300}It has powerful string handling.** If you want to search, substitute, justify, format, trim, delimit, interpose, or tokenize, you can probably use one of the built-in methods. If not, you can build on them to produce what you need.
1. **{color:#993300}It has few exceptions to its rules.** The syntax and semantics of Ruby are more self-consistent than most languages. Every language has oddities, and every rule has exceptions; but Ruby has fewer than you might expect.
1. **{color:#993300}It is laced with syntax sugar.** (To paraphrase Mary Poppins: A spoonful of syntax sugar helps the semantic medicine go down.) If you want to iterate over an array x by saying *for a in x*, for example, you can.
