
Once upon a time there was a Rails developer who wanted to become a Rails contributor. Deep down, he even wanted to become a member of the Rails core team! So one day, he decided to take the first step: he downloaded the Ruby on Rails source code!
So I downloaded the Rails source code:
$ git clone git@github.com:rails/rails.git
$ cd rails
$ ls
actioncable
actionmailbox
actionmailer
actionpack
actiontext
actionview
activejob
activemodel
activerecord
activestorage
activesupport
Brewfile
ci
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Gemfile
Gemfile.lock
guides
MIT-LICENSE
package.json
rails.gemspec
RAILS_VERSION
railties
Rakefile
README.md
RELEASING_RAILS.md
tasks
tmp
tools
version.rb
yarn.lockDamn... there's so much stuff here... I know most of the Rails components, but there are also a few new features. Luckily, Rails has several guides to help me fill in the gaps.
Ok, so I have an overview of the structure of the Rails repository. And now?
Well, my goal is to contribute to Rails. The simplest - but still useful - contribution that can be made to an open source project is a contribution to documentation. Let's start with that.
Rails, I need to clone and configure it to have an easy way to update it up front:
$ cd
$ mv rails rails_upstream
$ git clone git@github.com:<username>/rails.git rails_fork
$ cd rails_fork
$ git remote add upstream git@github.com:rails/rails.git
$ git fetch upstreamNow when I need to update my fork, I'm going to do the following:
$ git checkout master
$ git pull upstream master
$ git pushAnd when asked to rebase my branch on master, I do the following:
$ git checkout master
$ git pull upstream master
$ git push
$ git checkout <my-branch>
$ git rebase master <my-branch>
$ git push -fBy reading the ActiveStorage source code (activestorage/lib/active_storage/service.rb), I noticed a call to ActiveSupport: :notifications.instrument. I didn't know what it was, so I did some research:
The instrumentation API provided by Active Support allows developers to provide hooks that other developers can latch on to. There are several of these as part of Rails. With this API, developers can choose to be notified when certain events occur in their application or in another piece of Ruby code.
It's cool. There are several hooks added by ActiveStorage, so maybe not all of them are mentioned in the Active Support Instrumentation guide. I guessed right, three hooks are missing:
service_download_chunk.active_storageservice_update_metadata.active_storagepreview.active_storageI think I've found my first Rails:D
$ git checkout -b add-activestorage-instrumentation-hooks-to-guide
$ # apply wanted modifications to guides/source/active_support_instrumentation.md
$ git add guides/source/active_support_instrumentation.md
$ git commit
$ git push -u origin add-activestorage-instrumentation-hooks-to-guideImportant: since this commit only changes the documentation, it is important to add [ci skip] to the commit message so that the CI is not overloaded unnecessarily. Now that my branch is pushed, I need to go to https://github.com/rails/railsand open a new pull request.Pull Request:https://github.com/rails/rails/pull/36010
commit 78260d5663702f153f6bae64073f9659de366946
Author: Younes SERRAJ <younes.serraj@gmail.com>
Date: Wed Apr 17 19:25:46 2019 +0200
Mention more ActiveStorage hooks in Active Support Instrumentation guide [ci skip]
Hooks added:
- `service_download_chunk.active_storage`
- `service_update_metadata.active_storage`
- `preview.active_storage`
diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index e5ed283c45..4868b00bbe 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -545,6 +545,14 @@ Active Storage
| `:key` | Secure token |
| `:service` | Name of the service |
+### service_download_chunk.active_storage
+
+| Key | Value |
+| ------------ | ------------------------------- |
+| `:key` | Secure token |
+| `:service` | Name of the service |
+| `:range` | Byte range attempted to be read |
+
### service_download.active_storage
| Key | Value |
@@ -582,6 +590,23 @@ Active Storage
| `:service` | Name of the service |
| `:url` | Generated URL |
+### service_update_metadata.active_storage
+
+| Key | Value |
+| --------------- | ------------------------------ |
+| `:key` | Secure token |
+| `:service` | Name of the service |
+| `:content_type` | HTTP Content-Type field |
+| `:disposition` | HTTP Content-Disposition field |
+
+INFO. The only ActiveStorage service that provides this hook so far is GCS.
+
+### preview.active_storage
+
+| Key | Value |
+| ------------ | ------------------- |
+| `:key` | Secure token |
+
Railties
--------Now there is one very difficult thing to do: wait. Wait for a member of the central team to review the withdrawal request and comment or merge it. Wait without reloading the Github page every 5 seconds. Just move on and wait for an email notification: the request has been merged.

I've started with ActiveStorage, I'll stick with it for now. I don't have any features to add to it, so from time to time I check the issues on Github for inspiration. The bug I found, related to ActiveStorage and fairly easy to fix, is the following: https://github.com/rails/rails/issues/35953
Great! Now I have my next contribution and this time it's the code. Code goes hand in hand with testing, so I need to prepare my development environment to run the Rails test suite. Scary, but nothing impossible:)
There are mainly two ways to do this: you can either install all the dependencies, or run everything in a virtual machine. Personally, I'm going to do both for the sake of learning, but I'll only mention the easiest method in this blog, that of the virtual machine. I followed this guide first: https://github.com/rails/rails-dev-box
After installing VirtualBox and Vagrant on my Debian 9.8, I ran the following commands:
$ # in the host:
$ cd
$ git clone https://github.com/rails/rails-dev-box.git
$ cd rails-dev-box
$ cp -r ~/rails_fork ./rails
$ vagrant up
$ vagrant ssh
$ # once in the virtual machine:
$ cd /vagrant/rails
$ bundleNotice that I copied my phonebook Rails_Fork inside the directory rails-dev-box in order to be able to connect via ssh to the virtual machine and access the source code I am working on (to run the tests) .Ok, now that I have my development environment ready to work, I have to run the tests first. I want to make sure that the tests run successfully before changing the ActiveStorage source code (so if they fail, I'll know it's because of my code changes and not a configuration error).
$ # in the virtual machine:
$ cd /vagrant/rails
$ bundle exec rakeAnd again: wait. Just... wait... for... it... to work.

Done. Yes, it's green! Note: as advised in the documentation, I will edit the code in the host and run the tests in the virtual machine. This way, I don't install any software on the virtual machine and I avoid accidental changes to package versions and the like.
$ git checkout -b active-storage-bmp-variants-supportNow I can add the following changes:
activestorage/lib/active_storage/engine.rb to fix the problem (here, I'm whitelisting a mime type so ActiveStorage knows it can create BMP variants)activestorage/test/models/variant_test.rb to test that ActiveStorage actually succeeds in creating a BMP variantActiveStorage/ChangeLog.md to let Rails developers know about the changes introduced by my commit.It was not very difficult to write this patch. The only part that gave me a bit of a run for my money was testing, as I'm used to RSpec, not Minitest. I read the existing tests to find out how to write my own, then I googled how to test a single file. In my case, I executed:
$ cd /vagrant/rails/activestorage
$ bundle exec ruby -Itest ./test/models/variant_test.rb`green I like that. I can now commit and push to Github:
$ cd /vagrant/rails
$ git add ./activestorage
$ git commit
$ git push -u origin active-storage-bmp-variants-supportPull request:https://github.com/rails/rails/pull/36051
commit bcf370d689673031073ba2ac5588afe41cc315c9
Author: Younes SERRAJ <younes.serraj@gmail.com>
Date: Sun Apr 21 19:07:22 2019 +0200
Allow ActiveStorage to generate variants of BMP images
diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 54fc949172..d524ecf7d6 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Permit generating variants of BMP images.
+
+ *Younes Serraj*
+
## Rails 6.0.0.beta3 (March 11, 2019) ##
* No changes.
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index fc75a8f816..cbb205627e 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -33,6 +33,7 @@ class Engine < Rails::Engine # :nodoc:
image/jpeg
image/pjpeg
image/tiff
+ image/bmp
image/vnd.adobe.photoshop
image/vnd.microsoft.icon
)
@@ -56,6 +57,7 @@ class Engine < Rails::Engine # :nodoc:
image/jpg
image/jpeg
image/tiff
+ image/bmp
image/vnd.adobe.photoshop
image/vnd.microsoft.icon
application/pdf
diff --git a/activestorage/test/fixtures/files/colors.bmp b/activestorage/test/fixtures/files/colors.bmp
new file mode 100644
index 0000000000..3cc1e8764d
Binary files /dev/null and b/activestorage/test/fixtures/files/colors.bmp differ
diff --git a/activestorage/test/models/variant_test.rb b/activestorage/test/models/variant_test.rb
index d98935eb9f..92e3384042 100644
--- a/activestorage/test/models/variant_test.rb
+++ b/activestorage/test/models/variant_test.rb
@@ -144,6 +144,17 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
assert_equal 33, image.height
end
+ test "resized variation of BMP blob" do
+ blob = create_file_blob(filename: "colors.bmp")
+ variant = blob.variant(resize: "15x15").processed
+ assert_match(/colors\.bmp/, variant.service_url)
+
+ image = read_image(variant)
+ assert_equal "BMP", image.type
+ assert_equal 15, image.width
+ assert_equal 8, image.height
+ end
+
test "optimized variation of GIF blob" do
blob = create_file_blob(filename: "image.gif", content_type: "image/gif")Note: Sometimes you have multiple commits in your change request. You may be asked to overwrite them to help keep the history as clean as possible. If we ask you, git rebase -i and Git commit --Amend are your friends. So I opened a pull request and... I waited. Yes, there is a lot of expectation in open source contributions. Keep in mind that core contributors have their paid work to take care of, their personal lives, and a lot of problems to read, and a lot of pull requests to review, and their own pull requests to work on, and mailing lists to keep up to date, etc. Yes, that takes time. Yes, we love them for the awesome work they do. Yes, when we start contributing it's frustrating to wait and we're almost banned from Github for refreshing our post request page too often, but that's okay. We're contributing to Rails and it's a great feeling because we can help other developers, we're learning more about Rails, and we're even more appreciative of the work that all of these contributors have done before us.
First of all, a big thank you to @eileencodes ❤ for his conference at the RailsConf 2015 Breaking Down the Barrier: Demystifying Contributing to Rails: https://www.youtube.com/watch?v=7zoD6NZy6vY Guys, if you've been playing with Rails for two or three years, you can probably contribute. My advice is this: read the issues on Github, test them to confirm that they are reproducible or ask for more details if needed, read the pull requests, when you find something new for yourself, don't just read the tutorials and documentation but also go read the source code. It doesn't matter if you don't understand everything that's going on, at least you're accumulating knowledge and slowly building an intuitive understanding of how Rails works. Before you know it, you'll be so familiar with the system that contributing to Ruby on Rails will be a breeze.
Peace and love my friends.