Posts tagged "open source"

Charlie Somerville recently tweeted he wished there was a good guide about maintaining open source software:

In between consultancy jobs and building projects for our clients, our team is directly involved in many Open Source Projects. So after exchanging some messages, I realized it would be useful to document some of the common practices we do at Plataformatec for maintaining Open Source Software.

Although this post is not a complete guide, it does share our experience of maintaining and working on the issues tracker of many projects like Rails, Simple Form, Devise, and lately Elixir.

Avoid burnout

One of the most important things when it comes to OSS is to avoid burnout. This is extremely important for small projects, which mostly depend on one or two contributors. If someone burns out in large projects, there is always someone else to take on the issues tracker and maintenance work until you gather your energy back.

For small projects though, if you need to step away, it likely means the project will go unmaintained for a while, which will just make the situation worse as issues will continue to arrive.

So a lot of what we will discuss here is meant to avoid burnout. Here are two examples:

  1. Avoid issues from piling on – it is likely that, if the issues tracker has 30 open issues, you will feel less and less compelled to work on them;

  2. Learn how to say “no” – merging code or features you are not a 100% comfortable with may makes thing worse. Every time there is a bug on that particular feature, you may feel less compelled to work on it or even not be willing to improve/refactor the code in the future, etc;

Of course different developers have different reasons to burnout, so whenever you find yourself lacking the energy to work on a project, try to understand why the energy isn’t there and find ways to avoid the problem from repeating in the future.

Contributing.md file

If you are hosting your project on GitHub, GitHub allows you to place a Contributing.md file with instructions on how to contribute to the project. For example, here are the files for Devise and Elixir projects.

Remember the community wants the same as you: the best for your Open Source project. So having detailed instructions on how to collaborate and contribute to the project helps both you and the community. You will have more detailed bug reports, better patches/pull requests, and other developers will find it easier to give back.

However keep in mind that there will still be incomplete or wrong reports from developers that didn’t read the Contributing.md file. That leads us to the next tip.

ABC (Always Be Closing)

If you have ever been to a sales workshop or read about how to improve your sales skills, it is very likely you have seen Alec Baldwin’s speech from Glengarry Glen Ross:

Although we are not doing any sales here, I strongly apply the concept of “Always Be Closing” to the issues tracker. I am always, actively, closing issues. Here are the main reasons I close open issues:

  • The user has not read the Contributing.md and have posted a bug report without the relevant information like OS, software versions, stacktraces, etc;

  • Users are asking questions on the issues tracker when a project has a specific channel for those, like a mailing list or a tag on Stack Overflow;

  • The proposed feature is too complex to not be worth the time that it requires to be implemented. Or you don’t see the possibility for the feature to be implemented in a medium-term plan;

Usually the first thing I do in the morning is to give a quick pass at my inbox looking specifically at open issues. Issues that are invalid or that cannot be acted on are closed with the proper message. In case the user provides the missing information after a bad bug report is closed, the issue will be reopened in the next morning. This activity only takes a couple minutes of your morning, which you can do while you sip your hot coffee. :)

Soon after I adopted this workflow, Vasiliy Ermolovich noticed most of the time I was closing issues with similar reasons, and he has created the extremely useful José vs OSS project which integrates with Firefox and Chrome to help me close issues more quickly. This project has probably saved me days of work!

Ask for contributions

The community is there to help you! There are many ways you can reduce your workload by interacting with the community:

  • Depending on the project, asking a sample application to reproduce the issue is extremely helpful. A lot of bug reports are closed after the reporter tries to reproduce the issue and, in the process, they find out the bug was caused by something specific to their application. It saves you precious hours from trying to reproduce a bug that you would never find!

  • If a user reports a bug, ask the user if he/she feels comfortable to send a pull request with a fix. If you have an idea of where the bug is, send the user links to the relevant part of code, and make it clear you are available in case there are any questions;

  • For Elixir, we are experimenting with tagging issues with their “perceived difficulty”, so users who want to contribute to the language can help you solve existing issues. I often list small/medium features we plan to tackle in there and often they are implemented by the community and sent as pull requests;

Find out what works for you and the community

The important thing is to find out what works for you, the other maintainers and the community. For example, while working on Elixir, I was used to close features requests that I could see that would not be part of the language in the next 6 months, even though they were features I liked too! This eventually led to some questions from the community about the approach taken in our issues tracker.

The truth is: if the feature is really useful, you will hear about it many more times! I explained the approach to the community and showed how not having such entries in the issues tracker helps us keep focus on actual bug reports and actionable tasks. Which led everyone to agree with this direction.

Try things and listen to the feedback and hopefully you will find a workflow that works nicely for everyone involved!

Be nice!

Finally, be nice and be polite! Let your contributors know that you appreciate their work as much as they appreciate yours!

What about you? Do you have any tips to share regarding OSS projects maintenance?

This week we released the first release candidate version of Devise that is fully compatible with Rails 4, and we’re bumping its version to 3.0. This version completely drops support for Rails 3.1 and Ruby 1.8.7, only keeping compatibility with both Rails 3.2 and Rails 4, running with Ruby 1.9.3 and 2.0.

This rc version took some time to get ready, we’ve been running a rails4 branch for some time already and one of the reasons was because of the changes required to make it compatible with the new strong parameters API from Rails 4. We are aware that some people have been using this branch since Rails 4.0 beta1 with success, and we’re now inviting you to try 3.0 rc with the recent release of Rails 4.0 rc1.

Devise stable

Together with the 3.0 beta version, we’ve released Devise 2.2.4 with a few enhancements and bug fixes, make sure to check the changelog to see the new goodies. All changes are also included in the rc version.

Simple Form

Simple Form has been running a 3.0 rc version for a couple months already, fully compatible with Rails 4 as well, and today we are releasing its release candidate version. In Simple Form master we just dropped support to the 3.x Rails series, focusing our work on Rails 4 compatibility from now on, due to a series of improvements in Rails 4 regarding form helpers – but don’t worry, we will be keeping a v2.1 branch with Rails 3.2 compatibility for a while.

We have some cool plans to improve the wrappers API even further, but that’s subject for another blog post :).

Responders

Responders has been around for quite some time already and we use it in most of our projects, so today we’re celebrating its 1.0 release candidate version, specially to support Rails 4.

Show For

Show For just got a new stable release, v0.2.6, with all the enhancements and bug fixes that were in master, plus a v0.3.0 rc version that adds Rails 4 support.

Mail Form

Mail Form also got a new 1.5 rc release with Rails 4.0 compatibility. Nothing else has changed from the current 1.4 version.

Has Scope

Has Scope is getting a new 0.6 rc version with Rails 4.0 compatibility, including a couple of fixes that were already present in master.

Compatibility

All these new releases are officially dropping support to Rails 3.0 and 3.1, and Ruby 1.8.7. We’ll keep compatibility with Rails 3.2 and 4.0 from now on, all of them on the same branches except for Simple Form which has different branches for each Rails version.

Wrapping up

We’ve got new hot releases for you to try out with Rails 4, please give them a try and let us know if you find any issue or have any feedback.

We’d also like to specially thank everyone involved in helping us getting these projects up and running in Rails 4, without you folks that’d have never been possible.

Enjoy <3

Besides the big and shiny features that Rails 4 holds, there’s a lot of small improvements on several other sections of the Rails framework – helpers, core extensions, app configurations and more – that might not even hit the Changelogs but will somehow make our lifes easier in the future. One of these hidden gems that I’ve found recently is an improvement on the content_for helper to flush and replace previous chunks of HTML with new ones.

The content_for that we are used to

The content_for method is an old friend of every Rails developer, and it’s a pretty simple and flexible helper. You can store a chunk of HTML from a String or a block, and grab it somewhere else in your views or yield it directly into your templates. It’s a pretty handy trick to move data from your views into your layouts, like page titles, custom meta tags or specific script tags that your page needs to include.

# On your 'application.html.erb' layout, inside the '<head>' tag.
<%= yield :metatags %>
 
# Then, into a specific view
<% content_for :metatags do %>
  <meta property="og:image" content="http://example.com/image.jpg" />
<% end %>

Multiple calls of the content_for helper using the same identifier will concatenate them and output them together when you read it back on your views, as:

<% content_for :example, "This will be rendered" %>
<% content_for :example do %>
  <h1>This will be rendered too!</h1>
<% end %>

On some scenarios this behavior might not be desired, and with Rails 4 you can flush out the stored pieces of an identifier and replace it instead of adding more content to it: using the flush: true option. The first implementation used an extra true argument, but we changed to use a Hash instead, so the flush key can express better the behavior we’re expecting.

<% content_for :example, "This will be rendered" %>
<% content_for :example, flush: true do %>
  <h1>But this will override everything on the ':example' block.</h1>
<% end %>

The gallery situation

I’ve stumbled upon this on a recent project, where we had a somewhat classic scenario: a partial named _gallery, responsible for rendering the piece of HTML to display a gallery of images that also supplies a content_for block with a script tag to include the required libraries to put the gallery to work.

<section class="gallery">
  <!-- a truckload of HTML tags -->
</section>
<% content_for :scripts, javascript_include_tag('gallery') %>

It works like a charm. But with an updated requirement we had the case where multiple galleries could be present on the same page, rendering the _gallery partial several times. The required HTML would be present, but the gallery.js script would be included multiple times into the rendered page. Instead of working this out using instance variables to check that the partial was rendered at least once, we could let Rails do all the hard work for us, using the flush option when including the gallery.js script.

<section class="gallery">
  <!-- a truckload of HTML tags -->
</section>
<% # We can render this partial several times and this script will be included just once %>
<% content_for :scripts, javascript_include_tag('gallery'), flush: true %>

Back to the present: Rails 3.2

Well, while this seems to be a perfect solution to my problem, this feature isn’t available on Rails 3.2 or on the 3-2-stable branch – it’s only available on the master branch that will be released with Rails 4. But, backporting this feature into a 3.x application is pretty simple, using a helper of your own.

def single_content_for(name, content = nil, &block)
  @view_flow.set(name, ActiveSupport::SafeBuffer.new)
  content_for(name, content, &block)
end

After some source diving into the ActionPack source code we’re done – it just needs to replace any present content with a brand new SafeBuffer instance before storing the piece of HTML.

What do you think about this little addition to Rails 4? Can you think of a similar problem that could be solved with this instead of a custom hack?

I’d like to start with a question: Have you ever seen code like this?

class User < ActiveRecord::Base
end
 
User.new.tap do |user|
  user.name     = "John Doe"
  user.username = "john.doe"
  user.password = "john123"
end

I have. But what few developers know is that many methods in Active Record already accept a block, so you don’t need to invoke tap in the first place. And that’s all because Active Record loves blocks! Let’s go through some examples.

Using blocks with Active Record

When creating an Active Record object, either by using new or create/create!, you can give a block straight to the method call instead of relying on tap:

User.new do |user|
  user.name     = "John Doe"
  user.username = "john.doe"
  user.password = "john123"
end
 
User.create do |user|
  user.name     = "John Doe"
  user.username = "john.doe"
  user.password = "john123"
end

And you can mix and match with hash initialization:

User.new(name: "John Doe") do |user|
  user.username = "john.doe"
  user.password = "john123"
end

All these methods, when receiving a block, yield the current object to the block so that you can do whatever you want with it. It’s basically the same effect as using tap. And it all happens after the attributes hash have been assigned and other internal Active Record code has been run during the object initialization, except by the after_initialize callbacks.

That’s neat. That means we can stop using tap in a few places now. But wait, there’s more.

Active Record associations also love blocks

We talked about using blocks when building an Active Record object using new or create, but associations like belongs_to or has_many also work with that, when calling build or create on them:

class User < ActiveRecord::Base
  has_many :posts
end
 
class Post < ActiveRecord::Base
  belongs_to :user
end
 
# has_many
user = User.first
user.posts.build do |post|
  post.title = "Active Record <3 Blocks"
  post.body  = "I can give tap a break! <3 <3 <3"
end
 
# belongs_to
post = Post.first
post.build_user do |user|
  user.name     = "John Doe <3 blocks"
  user.username = "john.doe"
  user.password = "john123"
end

That’s even better. That means we can stop using tap in a few more places.

Wrapping up: Active Record <3 blocks

It is possible to avoid extra work, sometimes simple stuff such as using tap with methods like new and create, other times more complicated ones, by getting to know what the framework can give us for free.

There are other places inside Active Record that accept blocks, for instance first_or_initialize and friends will execute the given block when the record is not found, to initialize the new one.

In short, next time you need a block when creating records using Active Record, take a minute to see if you can avoid using tap by using an already existing feature. Remember: Active Record <3 blocks. And don’t do that with blocks only, the main idea here is that you can learn more about the framework, and let it do more work for you.

How about you, do you have any small trick in Ruby or Rails that makes your work easier? Take a minute to share it with others in the comments. :)

Rails 4.0 – current master branch at the time of this writing – has recently got a small – yet very useful – addition: ActiveModel::Model. The implementation is really simple, as you can see below:

module ActiveModel
  module Model
    def self.included(base)
      base.class_eval do
        extend  ActiveModel::Naming
        extend  ActiveModel::Translation
        include ActiveModel::Validations
        include ActiveModel::Conversion
      end
    end
 
    def initialize(params={})
      params.each do |attr, value|
        self.public_send("#{attr}=", value)
      end if params
    end
 
    def persisted?
      false
    end
  end
end

Quite straightforward, huh? But what does it do, and what are we supposed to do with it?

ActiveModel::Model: Basic Model implementation

According to the docs, ActiveModel::Model includes all the required interface for an object to interact with ActionPack, using different ActiveModel modules. It includes model name instrospection, conversions, translations and validations. In addition to that, it allows you to initialize the object with a hash of attributes, pretty much like ActiveRecord does.

Wait, what? In short: you can easily extend ActiveModel::Model in a normal Ruby class and use instances of that class with helpers like form_for, dom_id / dom_class, and any other ActionView helper, as you do with ActiveRecord objects. It also gives you known method helpers such as human_attribute_name.

A minimal implementation could be:

class Person
  include ActiveModel::Model
 
  attr_accessor :name, :age
  validates_presence_of :name
end
 
person = Person.new(:name => 'bob', :age => '18')
person.name # => 'bob'
person.age # => 18
person.valid? # => true

This is really handy, considering that before this addition, we’d have to add all that code to have a model up and running to use with ActionView's form_for, for instance. Ok, it is not that much code to add, but now we don’t even need to remember which modules are required for such integration. And I have to add that I’ve been creating similar classes in different applications lately. Take a moment to think about a contact form, that does not need to be tied to a database: it’s a common scenario to implement using ActiveModel::Model.

Extending Basic Model even more

Note that, by default, ActiveModel::Model implements persisted? to return false, which is the most common case. For instance, when used with form_for, this means that the generated url would post to the create action. You may want to override it in your class to simulate a different scenario:

class Person
  include ActiveModel::Model
  attr_accessor :id, :name
 
  def persisted?
    self.id == 1
  end
end
 
person = Person.new(:id => 1, :name => 'bob')
person.persisted? # => true

Besides that, if for some reason you need to run code on initialize, make sure you call super if you want the attributes hash initialization to happen.

class Person
  include ActiveModel::Model
  attr_accessor :id, :name, :omg
 
  def initialize(attributes)
    super
    @omg ||= true
  end
end
 
person = Person.new(:id => 1, :name => 'bob')
person.omg # => true

And remember that, at the end, this is all Ruby: you can include any other module of your own and other ActiveModel modules easily in your class. For instance, lets add callbacks to our model to mimic ActiveRecord's save functionality:

class Person
  include ActiveModel::Model
  extend ActiveModel::Callbacks
 
  define_model_callbacks :save
  attr_accessor :id, :name
 
  # Just check validity, and if so, trigger callbacks.
  def save
    if valid?
      run_callbacks(:save) { true }
    else
      false
    end
  end
end

This gives you before_save, after_save and around_save callbacks. Quick and easy, huh?

Wrapping up

ActiveModel::Model is a really small, handy addition to Rails 4.0, which helps us to get classes that act more like ActiveRecord and easily integrate with ActionPack.

For more detailed information on other features available, please refer to the specific modules included in ActiveModel::Model. Each module includes plenty of docs explaining its functionality. Apart from these included modules, ActiveModel itself has a bunch of useful stuff to add to your Ruby classes that are really worth checking out.

This is the kind of thing that makes me a happier Rails developer every day. What about you, what makes you a happier Rails developer? Please take a moment to tell us in the comments section below :)

The Carnival is over in Brazil but we are still partying at Plataformatec by bringing you a complete new release of SimpleForm. This time is not a small bump though, it’s a shiny new version: SimpleForm 2.0, that comes with a bunch of new features and customizations, a new wrapper API to create custom input stacks and a great integration with Twitter Bootstrap.

Wrappers API

The new wrappers API is here in place of the old components option (besides some other *_tag and *_class configs), to add more flexibility to the way you build SimpleForm inputs. Here is an example of the default wrapper config that ships with SimpleForm when you run its install generator:

config.wrappers :default, :class => :input,
  :hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
  ## Extensions enabled by default
  # Any of these extensions can be disabled for a
  # given input by passing: `f.input EXTENSION_NAME => false`.
  # You can make any of these extensions optional by
  # renaming `b.use` to `b.optional`.
 
  # Determines whether to use HTML5 (:email, :url, ...)
  # and required attributes
  b.use :html5
 
  # Calculates placeholders automatically from I18n
  # You can also pass a string as f.input :placeholder => "Placeholder"
  b.use :placeholder
 
  ## Optional extensions
  # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup`
  # to the input. If so, they will retrieve the values from the model
  # if any exists. If you want to enable the lookup for any of those
  # extensions by default, you can change `b.optional` to `b.use`.
 
  # Calculates maxlength from length validations for string inputs
  b.optional :maxlength
 
  # Calculates pattern from format validations for string inputs
  b.optional :pattern
 
  # Calculates min and max from length validations for numeric inputs
  b.optional :min_max
 
  # Calculates readonly automatically from readonly attributes
  b.optional :readonly
 
  ## Inputs
  b.use :label_input
  b.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
  b.use :error, :wrap_with => { :tag => :span, :class => :error }
end

Wrappers are used by the form builder to generate a complete input. You can remove any component from the wrapper, change the order or even add your own to the stack.

The :default wrapper is going to be used in all forms by default. You can also select which wrapper to use per form, by naming them:

# Given you added this wrapper in your SimpleForm initializer:
config.wrappers :small do |b|
  b.use :placeholder
  b.use :label_input
end
 
# Uses the :small wrapper for all inputs in this form.
simple_form_for @user, :wrapper => :small do |f|
  f.input :name
end

Or you can just pick a different wrapper in a specific input if you want:

# Uses the default wrapper for other inputs, and :small for :name.
simple_form_for @user do |f|
  f.input :name, :wrapper => :small
end

You can see a more detailed description of the new wrappers API in the documentation.

Twitter Bootstrap

The second big change in SimpleForm 2.0 is out of the box Bootstrap integration. SimpleForm now ships with a generator option to initialize your application with a set of specific wrappers customized for Bootstrap. To get them, just run in your terminal, inside a Rails application (with SimpleForm already installed):

rails generate simple_form:install --bootstrap

This gives you the default SimpleForm initializer in config/initializers/simple_form.rb with some extra integration code added for Bootstrap. For example, here is the default wrapper:

config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', 
  :error_class => 'error' do |b|
  b.use :placeholder
  b.use :label
  b.wrapper :tag => 'div', :class => 'controls' do |ba|
    ba.use :input
    ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
    ba.use :hint,  :wrap_with => { :tag => 'p', :class => 'help-block' }
  end
end

This wrapper is setup with the same structure that Bootstrap expects and is set to be the default wrapper in your application. This is the killer feature in SimpleForm 2.0: the Bootstrap integration is not inside SimpleForm but all in your application. This means that, if you want to move away or customize Bootstrap in the future, you don’t need to monkey patch SimpleForm, everything is in your app!

We’ve set up a live example application showing most of the SimpleForm inputs integrated with Twitter Bootstrap, make sure you check it out! The application code is on github.

Keep reading this blog post to find out the other changes and deprecations that gave SimpleForm all this extra flexibility, allowing it to be easily integrated with Twitter Bootstrap 2.0.

New configs

SimpleForm 2.0 comes with some new configs to ease its integration with Bootstrap and to make your daily work even more flexible:

  • default_wrapper: defines the default wrapper to be used when no one is given.
  • button_class: defines a class to add for all buttons.
  • boolean_style: change the way booleans (mainly check boxes and radio buttons) are shown: :inline (the default) uses the same structure as before, checkbox + label; :nested (generated for new apps) puts the checkbox inside the label, as label > checkbox.
  • collection_wrapper_class: class to add in all collections (check boxes / radio buttons), given collection_wrapper_tag is set.
  • item_wrapper_class: class to add to all items in a collection.
  • generate_additional_classes_for: allows you to specify whether to generate the extra css classes for inputs, labels and wrappers. By default SimpleForm always generate all classes, such as input type and required info, to all of them. You can be more selective and tell SimpleForm to just add such classes to the input or wrapper, by changing this config.

Deprecations

In order to create the new wrappers API, we had to deprecate some configs and change some helpers, so here is a basic summary of what is being deprecated:

Configs

  • translate: By making placeholder and hint optional options in the wrappers API, you can already disable the automatic translation attempt that happens for these components. labels, on the other hand, are always used in forms, so we added a special config for them: translate_labels.
  • html5: this config is now part of the wrappers API, with b.use :html5, so the config option has been deprecated.
  • error_notification_id: in favor of using error_notification_class only.
  • wrapper_tag=, wrapper_class=, wrapper_error_class=, error_tag=, error_class=, hint_tag=, hint_class=, components=: all these were moved to the wrappers API structure, and are not required anymore.

Helpers

  • :radio input type: In order to integrate with Bootstrap, we had to get rid of the :as => :radio and use :as => :radio_buttons instead. The former still works, but will give you a bunch of deprecation warnings. CSS class names changed accordingly as well
  • collection_radio: has changed to collection_radio_buttons to follow the :as => :radio_buttons change. Its label class has changed as well based on the helper name.

Wrapping up

SimpleForm 2.0 comes with a lot of new features, in special the new wrappers API, to make it flexible enough to allow you to customize inputs as much as possible in an easier way, and to bring you the integrated Bootstrap structure.

Make sure you check out the new SimpleForm README and also the CHANGELOG for a full list of changes. We’ve also created an special wiki page to help you Upgrading to SimpleForm 2.0.

If you find any trouble while migrating to 2.0, or any issue with Bootstrap integration, or any other issue, please let us know in the issues tracker. And if you have any questions, make sure to send them to the mailing list, there are a lot of people there to help you.

All our development team and an amazing number of contributors put a lot of effort into this new release and we hope you will enjoy it. SimpleForm 2.0 + Bootstrap: from us, for you, with love.

Thoughts about SimpleForm 2.0? Please let us know in the comments.