Cleaning up your CSS with selectors
I noticed that one of the input fields on one of our sites was not being styled properly. For the project, we're using the Ruby on Rails gem simple form for generating our forms. In addition to reducing a lot of duplicated code in your forms, it also generates ids for every input. We were using these ids to style 'exceptional' elements.
For instance, we had some fields that only excepted two or three characters, and we styled the input width to match with the following.
Because one of the fields that accepted up to three characters wasn't in this list, it wasn't being styled pro perly. One fix could have been to add that field to the list, but using CSS selectors, we can solve the bug in a better manner.
These rules will match all elements of the number type, with a size of two and three respectively. By using these rules, as opposed to explicitly listing out which elements we want the styling to apply to or adding a CSS class, there is nothing special we need to remember to do when adding a new element. Everything just works.
請求書.jpのスタンドファーム社への譲渡について
この度、平成 24 年 4 月 15 日をもって請求書.jpを弊社よりスタンドファーム株式会社へ完全譲渡し、スタンドファーム社の運営するクラウド請求書管理サービス「misoca」へ移行することとなりました。
The Joy of Gems: Cooking up Rails Plugins
Last night I presented at Cookpad’s Tokyo Rails event. This installment had the largest turn out I’ve seen so far, with at least forty participants. I think word’s gotten out that Tokyo Rails has the best food of any Ruby group in the city (and great people too)! This time we had some great home cooked Korean food.
My presentation was about converting Rails plugins to gems. Fortuitously, there was an announcement last week that vendor/plugins will be deprecated, and gem plugins would become the standard way of building a Rails plugin. So the timing of my presentation worked out great.
Unfortunately, I don’t think my slides showed up so well on the projector. I’ve attached them below, so if anyone is interested, please have a look at them.
Dynamic Methods vs. Method Missing
For a class I'm organizing on metaprograming in Ruby, we’re using Metaprograming Ruby as a textbook. In the chapter Tuesday: Methods, the book introduces two techniques for removing duplication: dynamically defining methods and using method_missing. It gives examples of applying both techniques to some sample code of which a simplified version is reproduced below:
# initial code
class Computer
def initialize(data_source)
@data_source = data_source
end
def mouse
puts "Price: #{data_source.mouse_price}"
end
def keyboard
puts "Price: #{data_source.mouse_price}"
end
def monitor
puts "Price: #{data_source.mouse_price}"
end
#...
end
# dynamic methods
class Computer
def initialize(data_source)
@data_source.methods.grep(/^(.*)_price$/) { Computer.define_component $1 }
end
def self.define_component(name)
define_method(name) do
puts "Price: #{data_source.send("#{name}_price")
end
end
end
# method_missing
class Computer
instance_methods.each do |m|
undef_method m unless m.to_s =~ /^__|method_missing|respond_to?/
end
def method_missing(name, *args)
super if !respond_to?(name)
puts "Price: #{data_source.send("#{name}_price")
end
def respond_to?(method)
@data_source.respond_to?("#{name}_price")
end
end
However, the book doesn't discuss when you should use one technique versus another. Here’s my rule: only use method_missing when it is infeasible to use dynamic methods.
One good example of using method_missing is ActiveRecord's find_by method. With it, you can call a method like find_by_name_and_birthdate. While ActiveRecord could theoretically use the dynamic method technique, generating every possible method would be overkill, thus using method_missing makes sense.
One counter example can be found in an example in the Metaprograming Ruby book itself:
class Roulette
def method_missing(name, *args)
person = name.to_s.capitalize
super unless %w[Bob Frank Bill].include? person
number = 0
3.times do
number = rand(10) + 1
puts "#{number}..."
end
"#{person} got a #{number}"
end
end
In this case, we have three methods we want Roulette to respond to: bob, frank, and bill. As we know these methods in advance, you should use the dynamic_method strategy:
class Roulette
%w[bob frank bill].each do |name|
define_method name do
number = 0
3.times do
number = rand(10) + 1
puts "#{number}..."
end
"#{name.to_s.capitalize} got a #{number}"
end
end
end
Now back to our initial example with Computer, which technique should we apply? Given that we can apply the dynamic methods technique, we should use it. Oh, and assuming we are always passed an instance of DataStore, I'd refactor it like so:
# dynamic methods
class Computer
DataSource.methods.grep(/^(.*)_price$/).each do |name|
define_method(name) do
puts "Price: #{data_source.send("#{name}_price")
end
end
end
Guessing a String's Encoding Under Ruby 1.9
For our Japanese invoicing solution, 請求書.jp, we record the initial HTTP referrer for each user who signs up to our service. Search engines have standardize on the q parameter to represent a search query, such as 請求書テンプレート, so we use this parameter to guess what query a user signs up by. Unfortunately, search engines have not standardized on an encoding to use, and the query parameter can be encoded in any one of UTF-8, EUC-JP, or Shift_JIS. To work around this, we use the following Ruby 1.9 code:
This code allows us to try each of the three expected encodings, and then encode the result into UTF-8 for display within our admin interface.
PDF generation and Heroku
For 請求書.jp, we wanted to provide our users with a way to generate PDF versions of invoices. We used the PDFKit gem (https://github.com/jdpace/PDFKit), which by itself is a thin wrapper around wkhtmltopdf (http://code.google.com/p/wkhtmltopdf/), to easily generate PDFs. With this tool chain it is possible to generate PDFs for any page, using the HTML and CSS you already have in place.
Installation
Installation is quite simple:
- add PDFKit to your Gemfile, install the wkhtmltopdf-binary gem
- add the following to your config/application.rb (Rails 3) to hook PDFKit into Rack:
config.middleware.use PDFKit::Middleware
- add an initializer (config/initializers/pdfkit.rb) like this:
PDFKit.configure do |config| config.default_options = { page_size: 'A4', print_media_type: true } end
Basically that’s it, but please see https://github.com/jdpace/PDFKit for more details. Anyway, pretty easy, no?
Getting it to work on Heroku
Well, the tricky part starts when you want to deploy this to Heroku.
First, you’ll need to include a statically linked 64bit Linux version of wkhtmltopdf in your application. You can download it from http://code.google.com/p/wkhtmltopdf/downloads/list (wkhtmltopdf-0.10.0_rc2-static-amd64.tar.bz2 for instance). To use the same binaries in development and production, we removed the wkhtmltopdf-binary gem again, downloaded the binaries for Linux and Mac so all our development environments are covered, and extended config/initializers/pdfkit.rb like this:
PDFKit.configure do |config|
config.default_options = { page_size: 'A4', print_media_type: true }
if RUBY_PLATFORM =~ /linux/
wkhtmltopdf_executable = 'wkhtmltopdf-amd64'
elsif RUBY_PLATFORM =~ /darwin/
wkhtmltopdf_executable = 'wkhtmltopdf-osx'
else
raise "Unsupported. Must be running linux or intel-based Mac OS."
end
config.wkhtmltopdf = Rails.root.join('vendor', 'bin', wkhtmltopdf_executable).to_s
end
After deploying to Heroku, the second issue you are likely to notice is the following: Requesting a PDF page just sits there for a while and then returns an application error. That is because you are most likely using external stylesheets and wkhtmltopdf will request them in order to generate the PDF. But your Dyno is currently busy with generating the PDF, so it can’t respond to the incoming request regarding the stylesheets.
Unfortunately starting a second Dyno or using unicorn on the cedar stack doesn’t really help here, because Heroku’s router doesn’t know which Dynos are busy but rather distributes the workload according to different parameters. So basically doing a request from within your application to your application won’t work reliably. Putting a cache / CDN (like AWS’ cloudfront) in front of your assets mitigates the problem, but users might still see an application error because the cache / CDN needs to request those files from time to time. Serving all your assets altogether from S3 works of course, but makes deployment to Heroku harder.
The solution we employed in the end was to avoid the additional requests entirely and instead embed the printing styles into the HTML itself, using the following code in the layout (HAML):
!!!
%html{:lang => "ja"}
%head
%title= 請求書.jp
- if request_from_pdfkit?
%style{type: "text/css"}
= File.read(Rails.root.join("public","stylesheets","print.css"))
- else
= javascript_include_tag 'application'
= stylesheet_link_tag ‘application’
And in the application_helper.rb:
def request_from_pdfkit?
# when generating a PDF, PDFKit::Middleware will set this flag
request.env["Rack-Middleware-PDFKit"] == "true"
end
The downside of this solution is though that we need to have a static print.css in the public/stylesheets directory and can’t use Rails 3.1’s asset pipeline as before.
The third challenge we had to address was caused by using non-Latin script, Japanese in our case. To have Japanese script in the PDF, you need Japanese fonts installed on the server doing the PDF generation, so it can embed the font. There are no Japanese fonts installed on Heroku though. Fortunately we could come up with a way to install the required font within the Heroku environment. For that to work, we added the font to vendor/fonts in the Rails project and added the following initializer:
if Rails.env.production?
font_dir = File.join(Dir.home, ".fonts")
Dir.mkdir(font_dir) unless Dir.exists?(font_dir)
Dir.glob(Rails.root.join("vendor", "fonts", "*")).each do |font|
target = File.join(font_dir, File.basename(font))
File.symlink(font, target) unless File.exists?(target)
end
end
With this setup we can now reliably generate nice looking PDFs for our users.
A Step Towards Internationalizing the Japanese Ruby Community
Aaron Patterson’s opening keynote at this year’s RubyKaigi once again raised the issue of communication between Japanese and international Rubyists. This topic also came up in Akira Matsuda’s and Shintaro Kakutani’s presentations. I also gave a lightning talk where I presented some ideas for creating globally minded Japanese Rubyists. Helping to address the issues raised in these presentations is a goal I am working towards.
A key part in internationalizing the local community is involving Japan’s foreign residents. At last night’s asakusa.rb meetup, I was impressed that all the speakers gave presentations in English. Having around five foreigners listening was enough of an impetus for Japanese to speak in English, something that wouldn’t have happened if all participants were Japanese.
With Tokyo Rubyist Meetup, we are creating an opportunity for Japanese and non-Japanese Rubyists to get together. However, it will take more than a meetup every couple of months to create real change within the community. With that in mind, I created a survey for “Rubyを使っての英語学習”, asking participants for feedback on how they would like to combine using Ruby and learning English.
The result shows that people are most interested in interactive activities, such as pair programming or a workshop, in a small group or one-on-one basis. As a trial of this, I’ve created Drop in Ruby 英会話, which will have up to four participants come to our office, where we will talk about and use ruby together. By running this event in a casual manner, I hope to be able to adapt the session to the participants individual skill levels, and to get a better idea of how we can continue with this approach in the future.
Like learning a language, the most important thing in making the community more global is to try. As such, I intend to continue to explore different paths we can take to internationalization. Continued feedback from everyone is welcome. You can find me on Twitter as @pwim.
Rubyを使っての英語学習
Rubyは日本で開発されたプログラミング言語で、CRubyのコア実装に関わった多くのコントリビューター(貢献者)は、日本人です。 しかしながら、日本人ではないRubyユーザは、日本人よりはるかに多く存在します。 Web開発のフレームワークとして成功を収めているRuby on Railsを例にとっても、約1000人のコントリビューターの中で、日本人は1%以下です。これは、日本でRubyが十分に活用できていないことを表しています。
日本のデベロッパーが国際的なRubyコミュニティに参加できていない一つの理由に、言語の違いがあります。日本は歴史的な経緯や島国ということもあり、一般的な日本人は、日本人ではない人と話す機会があまりなく、まして英語を話す人との機会は、英語を得意としない周辺諸国と比べても多くありません。
昨年のRuby会議以降、私は日本のRubyコミュニティの国際化のために動いています。そのため、私のように東京に住んでいる、日本人ではないrubyistsのためのTokyo Rubyist Meetupを作り、日本人のrubyistsたちと集まることができています。このイベントはとても成功していますが、まだまだ改善の余地があります。
私は、英語学習とRubyを組み合わせたアイディアを模索しています。英語を学習する最もポピュラーな方法は、英会話学校に通うことです。しかし、英会話学校の先生は技術的な知識は持っておらず、Rubyについて語り合うことはできません。そこで、1つのアイディアとして、Rubyについて語り合える英会話学校形式のクラスを作ってみてはと思っています。これは、日本人が、英語で技術的なトピックについて話すいい練習の機会になると思います。
他のアイディアとして、英語でRubyの使い方を学ぶ講義形式のセミナーやコースも考えています。これは、日本人に技術的な英語の練習とRubyの学習を同時にできる機会を与えてくれます。
英語による1対1のペアプログラミングは、Rubyと英語のスキルが同時に改善するもう一つの方法です。ペアプログラミングでの開発は大変素晴らしく、それはコミュニケーションを頻繁に必要とし、技術的な英語を学ぶ理想的な方法だと思います。
もし、英語を上達したいと考えていたり、いくつかのアイディアに興味を持っていただけたなら、「Rubyを使っての英語学習について」のアンケートにご協力いただけますと幸いです。
よろしくお願いいたします。
Using the Asset Pipeline under Rails 3.1
請求書.jp allows Japanese freelancers and small businesses to easily create invoices. We’ve built it using Rails 3.0 in conjunction with Coffee Script and Sass, and host the application on Heroku. Although CoffeeScript and Sass have made developing the service easier, getting them setup on Heroku is a bit of a hassle. However, Rails 3.1 introduces the asset pipeline, which not only makes it easier to use CoffeeScript and Sass, but also handles the packaging of these resources into a single file for increased performance.
Although Rails 3.1 has not been officially released yet, it is out of beta and into the fourth release candidate. Given how attractive the asset pipeline was, I decided to give upgrading 請求書.jp a shot.
The biggest challenge was to find information about how the asset pipeline works. I was able to come across a couple articles and a presentation DHH gave, but overall the information was sparse on how it actually worked. The best success I had in understanding how everything worked was to generate a new rails project with 3.1 and then use the scaffold command to generate a simple resource. By studying the generated code, I was able to figure out how to convert our application. The following is a summary of the asset pipeline specific changes I made.
# Gemfile gem 'rails', '3.1.0.rc4' gem 'sprockets', '= 2.0.0.beta.10' # rails 3.1.0.rc4 compatible gem 'sass-rails', "~> 3.1.0.rc" gem 'coffee-script' gem 'uglifier' # app/assets/javascripts/application.js //= require jquery //= require jquery_ujs //= require ../../../vendor/assets/javascripts/externals //= require_tree . # vendor/assets/javascripts/externals.js: //= require ./jshashtable-2.1.js //= require ./jquery.numberformatter-1.2.2.min.js # app/assets/javascripts/invoices.coffee // Invoicing specific CoffeeScript that is dependent on jquery.numberformatter # app/assets/stylesheets/application.css /* *= require_self *= require_tree ./web */ # app/assets/stylesheets/_compatibility.css.sass /* Macros for browser compatibility */ # app/assets/stylesheets/web/*.css.sass @import compatibility /* Styling of various elements */ # app/assets/stylesheets/print.css.sass /* Print specific CSS */ # config/application.rb config.assets.enabled = true # config/environments/production.rb config.assets.compress = true config.assets.js_compressor = :uglifier
After getting everything migrated to the asset pipeline, the rest of the upgrade involved identifying outstanding issues in Rails 3.1. These issues appeared in places where I was doing something that was a bit unusual, such as accessing a relation in an after_initialize block or storing an unsaved ActiveRecord object to the session. Rather than delving into the internals of Rails, I’ve worked around these issues.
After resolving these issues, we deployed it to Heroku. There we discovered one issue - that the New Relic plugin isn’t compatible with Rails 3.1. Once removing the plugin, we had no other issues.
Upgrading 請求書.jp to Rails 3.1 took me a total of eleven hours. In its current state, Rails 3.1 is usable, but upgrading requires a fair amount of independent research and debugging. Once it is actually released, these hiccups should go away, and upgrading your application should go smoothly.
Updating a real world application to Rails 3
We have just finished updating one of our bigger projects from Rails 2.3.8 to 3.0.3 and wanted to share our experience.
The update process:
For the update we performed the following tasks:
- basic Rails 3 framework update, including new routes and switch to bundler
- update the gems and plugins, replace some gems / plugins with others or with custom code (see below)
- resolve Rails and shoulda deprecations
- adapt to Rails 3 new escaping behavior
- port all mailers to the new ActionMailer API
For the update process itself, we followed the various advise out there.
Finding replacements for the gems and plugins we used wasn't always straight forward. The replacements we had to do:
- AppConfig -> RailsConfig
- super exception notifier -> exception_notification and custom code using rescue_from to handle error display
- globalize2 -> globalize3
- subdomain_fu -> custom code; the new router already takes care of some of subdomain_fu's functionality
Some numbers:
To give you an impression of the size of the application, here are the sloccount numbers:
- test: 4047 sloc
- app: 2497 sloc
- vendor: 606 sloc
- config: 332 sloc
- lib: 188 sloc
Change statistics (taken from git, comparing before starting the upgrade with upgrade finished):
- all directories excluding vendor:
268 of 698 files changed with 2191 insertions, 1886 deletions - app, config, lib, test only:
260 of 263 files changes with 1957 insertions, 1801 deletions
As you can see, changes were needed to nearly every file in app, config. The main reason we also had to change so many test cases were the deprecations in shoulda.
In total we spent 51 hours on the upgrade, plus 10 hours debugging a very strange issue.
The basic update and getting our test cases running again took us around 2 days. Another 5 days we then spent mainly on:
- Resolving deprecations and minor issues which were caused by changed behavior in new Rails or gems.
- Updating our own plugins and gems. This was rather challenging because for some parts of Rails the documentation is still lacking or outdated.
- The new escaping behavior wasn't caught by our test cases. So manual testing to find any escaped HTML chunks in was required.
- Locale in URL handling: The new router still isn't flexible enough and we couldn't DRY this up completely. For simpler sites routing-filter works nicely though.
All in all, the update took a bit longer than we expected (which was about a week). We attribute this to the amount of detail that needed to be addressed.


Social Links