santiago.pastorino

ActiveModel::Serializers Rewrite (upcoming 0.9.0.pre version)

Posted by santiago.pastorino
on October 15, 2013

First of all, I want to apologize to all for the long time it has taken me to push this humble new code.

I started to work on ActiveModel::Serializers because I'm interested in the Rails API project in general and ActiveModel::Serializers in particular. Given that ActiveModel::Serializers has few contributors, I thought it could be a good opportunity to understand the code and help the community around the project.

I began contributing to the project on a trip to San Francisco. There, I had the opportunity to work a bit with Yehuda Katz and Tom Dale at Tilde, but when I returned back to my job at WyeWorks, day-to-day responsibilities did not allow me to continue the project at the same velocity and manner I would have liked. This, in part, explains the above mentioned delay.

You can check out the code following this link

Improvements

The code structure after the rewrite is pretty similar but with a number of advantages I will try to share here with you:

The code is cleaner and clearer to understand and maintain.

The following is a list of previous solutions that were either fixed or changed:

  • Refine method used here, which implemented a solution that I found complicated. Now at load time, associations create objects that represent each and hold needed options, instead of generating an anonymous class per association.

  • Associations knew the source and target serializer. That is, if we had a post serializer that had many comments, an object was created to represent the association recording, not only the comment serializer, but also the post serializer. Such visibility was eliminated in the rewrite. In fact, the responsibility of the associations object was changed as well. Now the responsibility is only that of building a serializer using the options specified for that association.

  • The fast_attributes solution and its invalidation strategy were removed.

  • Mutability as seen here and here. The previous solution passed a global hash that was modified by the objects that intervened in the solution. This is now changed using a more functional approach, decoupling objects and making them more testable.

  • ActiveModel::Serializer talked to the controller. This is now the responsibility of ActionController::Serializable.

  • ActiveModel::Serializer responsibility is to decorate the object we want to serialize but that contract wasn't honored in the previous code. Now there's no direct access to the serialized object and everything is done inside the serializer.

  • The responsibilities of a few objects were not very clear. For example, Association. Those were used to register associations to be serialized together with their respective options. In addition, it recorded the serializer origin and destination of the association. It also built a serializer for the target relationship. Lastly, it was responsible for initiating the objects serialization process and serialization of ids. Association current responsibility is only to construct and configure a serializer for the association.

  • Given the structure of the code and the new responsibilities, it is now easier to implement adapters for different formats.

The tests now make it easier to understand how each part of the code works, are better organized and make sure that everything gets tested.

There are test files organized by functionality:

├── fixtures
│   ├── active_record.rb
│   └── poro.rb
├── integration
│   ├── action_controller
│   │   └── serialization_test.rb
│   └── active_record
│       └── active_record_test.rb
├── test_helper.rb
└── unit
    └── active_model
        ├── array_serializer
        │   ├── meta_test.rb
        │   ├── root_test.rb
        │   ├── scope_test.rb
        │   └── serialize_test.rb
        ├── default_serializer_test.rb
        └── serializer
            ├── attributes_test.rb
            ├── filter_test.rb
            ├── has_many_test.rb
            ├── has_one_test.rb
            ├── meta_test.rb
            ├── root_test.rb
            ├── scope_test.rb
            └── settings_test.rb

A lot less code for equivalent functionality.

LOC went down by ~50% from 682 to 340.

Performance is much better than before.

But please try this out in your apps. I've ran Sam Saffron's Discourse benchmarks using Rails 4 and current master of AMS and the rewrite branch. Here you have the results.

Current master branch:

Starting benchmark...
Running apache bench warmup
Benchmarking /
Running apache bench warmup
Benchmarking /t/oh-how-i-wish-i-could-shut-up-like-a-tunnel-for-so/69
Your Results: (note for timings- percentile is first, duration is second in millisecs)
---
home_page:
 50: 51
 75: 53
 90: 55
 99: 237
topic_page:
 50: 84
 75: 87
 90: 91
 99: 142
timings:
 load_rails: 4786
ruby-version: 2.0.0-p247
rails4?: true
architecture: x86_64
operatingsystem: Darwin
kernelversion: 12.5.0
memorysize: 8.00 GB
virtual: physical

Rewrite branch:

Starting benchmark...
Running apache bench warmup
Benchmarking /
Running apache bench warmup
Benchmarking /t/oh-how-i-wish-i-could-shut-up-like-a-tunnel-for-so/69
Your Results: (note for timings- percentile is first, duration is second in millisecs)
---
home_page:
 50: 40
 75: 41
 90: 44
 99: 236
topic_page:
 50: 76
 75: 78
 90: 81
 99: 130
timings:
 load_rails: 4331
ruby-version: 2.0.0-p247
rails4?: true
architecture: x86_64
operatingsystem: Darwin
kernelversion: 12.5.0
memorysize: 8.00 GB
virtual: physical

Why is it faster? Because AMS now does less work in order to produce the same results. Plus, much of the work that used to happen per each request are now carried out at load time.

We have a new project maintainer

For some time, AMS has been somewhat inactive as a project. Thankfully, Steve Klabnik has been recently working a great deal on issues and merging pull requests. From now on, I will also be actively contributing to the project. My intention is to resolve all pending issues and pull requests.

What's next?

It would be great if you could test your applications against this new branch and report any issues. I successfully ran the Discourse tests applying this patch. That patch gives an idea of some of the changes introduced but, depending on what you're using, problems can show up. Consider yourself warned. :)

After all that, here I have my to-do list. Several people have offered help via mail, Twitter, etc. Please feel free to grab tasks from here and make them yours it if you'd like. I'll continue to work on these issues as well.

To-do list

  • Complete the CHANGELOG of version 0.9.0 (part of this post can be reused)
  • Write the project's RDoc
  • Make the current format interchangeable
  • Tests for MongoID
  • Make Rails 4 controller generator output code that responds to JSON. This was true for Rails 3.2 but currently not with Rails 4.
  • Think more about the filter method. Should it filter by association name or by serialization keys? This is probably easier to explain with code. For example: def filter(keys); keys - [:comments]; end versus def filter(keys); keys - [:comments, :comment_ids]; end.
  • Re-implement merge_assoc which cached serialization output to improve performance for larger serialization operations. We could change the current implementation with a per-serializer output cache.
  • Implement the JSON API format
  • Add support for polymorphic associations
  • Come up with a better caching solution
  • Re-add Serializer#schema
| |
santiago.pastorino

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, which has public access for everyone to push documentation changes only.

Rails 4 MindNode

Overview

Upgrade

Active Support

Action Mailer

Active Model

Action Pack

Active Record

Railties

Security

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.

| |
santiago.pastorino

Rails 4 in 30'

Posted by santiago.pastorino
on October 29, 2012

I gave a presentation in RubyConf Argentina about what's new in Rails 4 (if you saw it please rate it). I've already posted the Rails 4 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.

| |
santiago.pastorino

Rails 4 in a MindNode

Posted by santiago.pastorino
on September 20, 2012

I'll be talking at RubyConf Argentina, 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 …

Rails 4 MindNode

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

UPDATE #2: Turbolinks

| |
santiago.pastorino

Ruby Refinements landed in trunk

Posted by santiago.pastorino
on August 03, 2012

Refinements arrived to Ruby trunk here 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

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 (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

| |
santiago.pastorino

Rails for API applications (rails-api) released

Posted by santiago.pastorino
on April 20, 2012

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?. 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 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 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 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.

| |
sebastian.martinez

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.

Congratulations!

| |
santiago.pastorino

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 to Bundler that avoids calling Bundler.setup which adds unnecessary overhead.

I was researching on a huge Bundler 1.1 performance regression, @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) 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 right before shelling out to run rails runner ''. The second call is on boot.rb as part of the boot process (well actually it's required from bundle exec through this rubyopt and on boot.rb the require returns false because it's already required). And the last call starts on config/application.rb which ends up calling Bundler.require 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 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 needed to run the command you are passing to bundle exec. I've patched 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

| |
santiago.pastorino

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 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, 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.

| |
sebastian.martinez

Client - Developer relationships

Posted by sebastian.martinez
on April 11, 2011

There is an old joke that illustrates how the relationship between clients and developers is that I'd like to share with you:

A man is flying in a hot air balloon when realizes he is lost. He reduces height and spots a man down below. He lowers the balloon further and shouts: 
- "Excuse me, can you tell me where I am?"
The man below says: 
- "Yes you're in a hot air balloon, hovering 30 feet above this field."
- "You must be a software developer," says the balloonist.
- "I am," replies the man. "How did you know?"
- "Well," says the balloonist, "everything you have told me is technically correct, but it's of no use to anyone."
The man below says, 
- "You must work in business as a manager."
- "I do," replies the balloonist, "but how did you know?"
- "Well," says the man, "you don't know where you are or where you are going, but you expect me to be able to help. You're in the same position you were before we met but now it's my fault." 

Developing successful client relationships are critical to any business. Preserving these relationships is crucial for making the time spent on projects more enjoyable and satisfying, as well as for referrals and future business.

So how can I improve this relationship?

It ain't the purpose of this post to be a silver bullet, but to share some practices that have given us some good results in the past.

  • Spend some time getting to know your client

    You will likely spend many hours with the client during the project. It is important in order to strengthen the relationship to get to know your client's interests, try to feel what they feel. After all, we are all human thus have natural highs and lows, and it is important to understand when someone is having a hard day.
  • Educate your client

    Educating clients about web development is crucial to the success of a project. The pace of change on the web is staggering and it is our responsibility to help clients make good decisions regarding their web presence. You need to tell your client that changes are a good thing and should be welcomed.
  • Be willing to say NO

    In many cases, clients ask us to do things that our experience says that doing so will, far from contributing to the project, cause users to run away. You need to take the time to understand why your client is asking you to do this, let them know your reasons against it, and try to find another solution together. This is healthy. Don't just say "yes" because the client is always right.
  • Be willing to say YES

    Say yes to the jobs that may require you to work harder. The client will be grateful. Specially in those cases when it is important for the client to have this particular feature deployed, as it will represent and lead to a full stack of opportunities. Doing this will make you more valuable in your clients eyes, and also by sharing the stress of the deadline you'll become closer to the client, so don't be afraid to embrace these opportunities. Now, this concept should not be taken as the regular way to go, meaning no one can expect us to work every single day giving a 150%. Pushing yourself a little bit every once in a while is ok, but when it becomes normal, then something's wrong.
  • Keep your distance

    We become more valuable the more we work in an organization, but we need to define and maintain our role clearly. Even as we build the relationships that make us successful, we need to be diligent in keeping our distance so we can continue to provide valued advice and expertise. The idea is to have a respectful relationship, always keeping it professional.
  • Be transparent

    There might be cases when some tasks take longer than you expected. What should you do then? **Be transparent.** Explain your client the complications you ran into, and that these complications will probably make you work a little bit longer on this task, there's nothing wrong with that. Anything can get complicated. Complications are part of our job. Being transparent to your client about this is definitely the way to go.
  • Gain your client's TRUST

    Best way to gain your client's trust is to stay focused on your deliverables. When we deliver **what** we say and **when** we say we will deliver it, we build our credibility and enhance our relationships. The trust the client gives us increases, and will help us when we state "this task will take two days" for example, when they think it's just a simple tweak and shouldn't take more than a couple of hours. The most important thing is letting them know that we are part of the team, we are both on the same boat, aiming to the same goals. Once your client understands that their failures are also your failures, and their achievements are your achievements as well and the other way around, then you'll be a step further in gaining their trust.
  • Work at it

    Recognize that the client relationship is part of the job. Working on the relationship will make you more successful on current projects, enhance your chance for future work, and make the project much more enjoyable.

Hopefully by following this you'll have a smoother relationship with your clients, and what's more, make you feel comfortable working with them on the daily basis.

| |
jose.costa

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) is a passionate agile software craftsman and founder of the Orlando Code Dojo group, where programmers get together to practice coding to improve their skills once a month. He is currently working at Envy Labs

Thanks for your time and great vibe!

| |
santiago.pastorino

Metaprogramming in Ruby slides from my talk at RubyConf Uruguay

Posted by santiago.pastorino
on November 04, 2010
| |
sebastian.martinez

Creating your own generators on Rails 2.3

Posted by sebastian.martinez
on September 23, 2010

Time has come for me to write a Rails generator, and as you're guessing right now, my first step was taking a look at the Guides They give you a pretty good idea on what you can do (despite of being for Rails 3.0), but as my friend Santiago always say, there's no better documentation than the source code itself. So, my second step was to dive into the code You should definitely read the code, great stuff there.

After some time reading, I decided it was time for me to start playing around with that, so here it comes:

First thing you should know, is that all Rails generators are derived from a class called “Rails::Generator::Base.” But, if we derive our generator class from NamedBase instead of Base, then we’ll get the ability to take a name parameter from the script/generate command line. With that in mind, you can start writing the generator skeleton:

class WidgetGenerator < Rails::Generator::NamedBase
  def manifest
    record do |m|
      # Do something
    end
  end
end

In order to make the generator work on your Rails 2.3 application, you should place this file under 'lib/generators/widget/widget_generator.rb'

Is on the manifest method where the magic occurs. Depending on what exactly we want our generator to do, is what we're going to code inside it. In my case, I wanted to behave very similar to the scaffold, so I wanted a controller class, a model, views, migration, etc... You can look at the templates of the scaffold generator, they will give you a very clear idea on how to use them. Then, you should place your templates under 'lib/generators/widget/templates/'

In most cases, you will want your generator to receive several arguments. Best way is to have an initialize method to take care of that, just like this:


class WidgetGenerator < Rails::Generator::NamedBase
  attr_reader   :controller_class_name,
                :class_name
  attr_accessor :attributes
  
def initialize(runtime_args, runtime_options = {})
    super
    @name = runtime_args.first
    @controller_class_name = @name.pluralize.capitalize
    @attributes = []

    runtime_args[1..-1].each do |arg|
      if arg.include? ':'
        @attributes << Rails::Generator::GeneratedAttribute.new(*arg.split(":"))
      end
    end
  end

  def manifest
    record do |m|
      # Do something
    end
  end
end

Until now, we're just initializing the generator, but it's not doing anything yet. Let's add some action on our manifest method:

def manifest
    record do |m|
      m.template('controller.rb', "app/controllers/#{name.pluralize}_controller.rb")
      m.template('model.rb', "app/models/#{name}.rb")
      m.migration_template("migration.rb", "db/migrate", :migration_file_name => "create_#{name.underscore.pluralize.camelize}")

      m.directory(File.join('app/views', name.pluralize))
      for action in %w[ new edit show ]
        m.template(
          "view_#{action}.html.erb",
          File.join('app/views', controller_file_name, "#{action}.html.erb")
        )
      end
    end
  end

Cool, now we are generating a controller from our template, a model, a migration, among others...Nice!

You can also add a protected banner method, to display the usage of the generator right on the console:

protected
    def banner
      "Usage: #{$0} widget WidgetName [field:type, field:type]"
    end

And that's all !! You can now generate all the widgets you want. The command to run this would be:

$ ./script/generate widget MyWidget title:string viewing:integer

Have fun generating!!

| |
jose.costa

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), 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, 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 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!

| |
jose.costa

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!

| |