Return to 10to1.be

Under the Hat


Category: Rails

Localizing Javascript in your rails app

22 Mar 2011

On a recent project I had to translate some text inside my Javascript code. But I didn't want to use duplicate localization files so I looked for a framework so I could reuse the translations from my rails app. So no duplicate translation files, just the locales/\.yml* files used by rails.

Installation

Add the i18n-js gem to your gemfile.

gem "i18n-js"

Now add the following before_filter to your ApplicationController. This generates the Javascript translation file every time you render a page in development.

class ApplicationController < ActionController::Base
  before_filter :export_i18n_messages

  def export_i18n_messages
    SimplesIdeias::I18n.export! if Rails.env.development?
  end
end

Use it!

Before you can really start using the localizations, you have to set the current locale. Do this in your application.html.erb file. (But it doesn't really matter where you set it, just do it before the call to translate)

<%= javascript_include_tag "i18n" %>
<%= javascript_include_tag "translations" %>
<%= javascript_tag do %>
  I18n.defaultLocale = "<%= I18n.default_locale %>";
  I18n.locale = "<%= I18n.locale %>";
<% end %>

And now just translate the same way you do in your rails app.

I18n.t("user.name") // returns 'Name'

Here is an example of my en.yml file.

en:
  user:
    name: "Name"
    children: 
      zero: "no children"
      one: "%{count} child"
      other: "%{count} children"

Other shizzle

Using number in your locales with pluralization.

I18n.t("user.children", { count: 0 }); // 'no children'
I18n.t("user.children", { count: 1 }); // '1 child'
I18n.t("user.children", { count: 3 }); // '3 children'

Use a default value when no translation is present.

I18n.t("user.age", { defaultValue: "Age" }); // 'Age'

Use localizations for number formatting.

I18n.l("number", 1990.99); // '1,990.99'

For more info check Github.

ActiveRecord, Postgres and schemas, lots of them

07 Mar 2011

The problem

One of the projects I'm working on requires me to read a lot of data from multiple d2r servers using SPARQL. Because the data on these servers can sometimes be similar the data has to be filtered before it is made available to a Rails app that will be displaying the data.

I didn't want to litter the database of the Rails app with this duplicate data (because it will feed a d2r server in the future), and fetching 10 rows of the server already took some seconds. So fetching all of the data from multiple servers would take quite a long time.

So I needed a place to store this temporary data separately where it wouldn't bother the data of the Rails app, and be available for filtering when all of the data was fetched. A separate schema for each of the servers would do the job.

Here's how it goes

I didn't load the entire Rails environment for this; this way AR doesn't automatically load the database connection parameters and we can easily adjust them ourself:

dbconfig = YAML::load(File.open(File.dirname(__FILE__) 
        + "/../../config/database.yml"))
@database_connection = dbconfig[Rails.env]
AR::Base.establish_connection(@database_connection)

Creating the schema wasn't that difficult, executing some SQL on the connection did the trick...

AR::Base.connection.execute("DROP SCHEMA 
   IF EXISTS #{@server_name} CASCADE")
AR::Base.connection.execute("CREATE SCHEMA #{@server_name}")

After that we have to alter the connection so AR does all future operations on the newly created schema.

@database_connection[:schema_search_path] = @server_name
AR::Base.clear_all_connections!
AR::Base.establish_connection(@database_connection)

If you do intend to use the entire Rails environment, be sure to do this before the classes are loaded, so they inherit the correct connection. If not you could unload the classes using ActiveSupport::Dependencies.clear.

But in this case I was loading the classes manually, and fetching the data from different servers in different processes. That way the loaded model classes couldn't interfere with each other.

With all the fetching processes finished, the data is ready to be filtered and loaded into the database of the Rails app, and be the source database for another D2R server.

Fancy a Natter ?

25 Oct 2010

What's a Natter?

natter |ˈnatər| informal
verb [ intrans. ]
talk casually, esp. about unimportant matters;
chatter : they nattered away for hours.

Most of us here at 10to1 are avid Twitter users and being the social media experts geeks that we are we've also got a Facebook account. The problem is; we like Twitter much more than we do Facebook. So when a Facebook-friend commented on something we've posted via Twitter, we didn't know it until hours later.

So we felt an itch and the Rails Rumble was an excellent excuse to scratch it.

What's a Rails Rumble?

The Rails Rumble is an annual 48 hour web application development competition in which teams of skilled web application developers get one weekend to design, develop, and deploy the best web property that they can, using the power of Ruby and Rails.

We (Jelle, Koen and me) teamed up with Nick to participate in this year's event. We did the nuts and bolts while Nick made sure the app looked as well as it does.

And it sure as hell looks as tight as we could have hoped for.

Zot Franske

Since we only had 48 hours to make it, we didn't get in as much features as we wanted but all the basics are there.

  • Did we have fun? Yes.
  • Will we participate again? Yes.
  • Are we proud of our 13th place? Yes. (13 is the new 1)
  • Did we sleep much? No. (OK: I overslept for 6 hours; quit whining Jelle)
  • Did it have bugs? Yes, some.
  • Could we have done it without Rails? No. (Okay, maybe in Sinatra)
  • Will we push the app even further? Yes. (It got an update last night, which fixed some bugs and made some performance enhancements).

How does it work?

After you sign up with Natter, it will listen to your tweets and post them to Facebook, enhancing them to atual Facebook posts if they contain an URL or an image.

Example

Now, dear reader, I can tell you're not impressed but here's the kicker; whenever a Facebook-user posts a comment to a Natter posted tweet on Facebook, Natter will post this comment on Twitter. And, you can reply to it, straight from the confines of your sweet minimal (before they redesigned) Twitter.

So now you've gone full circle for al your social networking needs. (Unless you're one of thos Jaiku or IRC guys)

Yeah, but how does it work?

We couldn't have done it without standing on some pretty big shoulders; so we're using (like most of our webaps) Rails coupled with the following gems: twitter_oauth for handling all things Twitter, facebook_oauth for all things Facebook, bitly to make the Facebook links small and kinda sexy (I'm stretching the limits of sexy here, it's more javacool and to make sure the server can handle it all we're using Resque for queuing all background jobs (pretty much everything is a background job).

The whole thing is hosted on a, Rails Rumble supplied, Linode slice which also hosts our MySQL db. We've only brought it down once, and that was pretty much our own fault (note to future self: decide who puts the indexes on the DB), so it's safe to say Linode rocked.

What did we learn?

  • A sexy design works
  • A painless signup process works
  • Sleep is overrated
  • We need to prepare better (Texts, flow of the app, design sketches,...)
  • Testing stuff like this was hard. (Study up on how to test your app)
  • Hard deadlines work (We could only submit our final build 10 minutes before the deadline)
  • Sysadmin-skillz (or rather devops /ht @frank_be) are needed
  • Being able to split up your app in tasks suited for one person, is a plus.

PDFKit and Ruby on Rails

18 Aug 2010

I finally found some time to write my first blog post for my awesome company! Here we go...

For a recent project I decided to use PDFKit to generate PDF files in Ruby on Rails. I'm used to generating these with Prawn, but as we all know it can be very hard to get it styled correctly.

Installation

First things first, we have to install the gem and then the wkhtmltopdf binary.

Installing the gem is easy:

gem install pdfkit

Hey, installing the binary is as easy:

sudo pdfkit --install-wkhtmltopdf

Now we can use PDFKit on our system.

Manual generation

To generate a pdf from a HTML web page just create the kit instance:

kit = PDFKit.new "<p>This is an awesome pdf.</p>"

And then convert it to a pdf file:

pdf = kit.to_file file_path

You can also pass an URL of a file to the PDFKit initializer method:

kit = PDFKit.new "http://www.10to1.be"
kit = PDFKit.new File.new(file_path)

Some Rails magic

But here is some real magic. You can just attach the pdf format to your controller actions. When you go to http://test.be/people/jelle.pdf, the PDF will be downloaded (or your browser will open it in a window).

Just include the following lines of code in your environment.rb (for Rails 2.x) or application.rb (for Rails 3.x):

require "pdfkit"
config.middleware.use PDFKit::Middleware

What happens now is that your show.html.erb file is rendered as usual but it is converted to the PDF format afterwards. So the PDf file gets the same style as the HTML page (with CSS styling included).

I used this for a project, and it works great!

Changing the filename

Now another handy way to change the filename for the PDF file. When you go to http://test.be/people/1.pdf, the downloaded filename will be 1.pdf. But what if I want the filename to be jelle-vandebeeck.pdf? Well, just include this line of code somewhere in your action:

def show
  @person = Person.find params[:id]
    
  # Change the filename of the downloaded pdf file
  headers["Content-Disposition"] = 
    "attachment; filename=\"#{@person.name}\""
end

For more information visit the Github page.

Fake data populator

23 Jul 2010

When you're building webapps, sooner or later you run into a screen where you want to list some data. An index page of all people for instance. There are many other cases where you want a lot of data, but for now, let's follow this path.

Say, you got thousands of people, you're not going to show them all on one page, do you? Probably you will use something like will_paginate.

Say, you want to see this pagination stuff in action, in your development environment. Since you are not going to manualy create a couple of thousand people, one option could be to set the number of results per page to 1 or 5 or 6 or ... well you know what I mean.

An other option, better option, is to use the populator and/or faker gem(s). The populator gems adds a method 'populate' to all Active Record models.

Person.populate(3000) do |person|
  person.first_name = "John"
  person.last_name = "Smith"
  person.number_of_shoes = 1..100
end

This will create 3000 people with the name John Smith. It becomes better when you throw in the faker gem.

Person.populate(3000) do |person|
  person.first_name = Faker::Name.first_name
  person.last_name = Faker::Name.last_name
  person.number_of_shoes = 1..100
  person.email = Faker::Internet.free_email
end

This will create 3000 people with random names, which is better if you ask me.

Want to present at Europe's biggest Open Source convention?

15 Dec 2009

For the third time, the Belgian Ruby community is organising a one-day developer's room with presentations on Ruby and Rails at FOSDEM (6 Feb 2010, Brussels).

FOSDEM is one of Europe's biggest conventions of people working on Open Source Software. This is a great opportunity to meet the brighest minds in the OSS world!

We're looking for people who want to share their passion about Ruby or Rails.

You can submit your proposal until until Monday, January 4, 2010. For more details, have a look at the call for papers

Even if you're not presenting, we love to meet you there!

Hirb

09 Dec 2009

A couple of weeks ago I watched the RailsCast on Searchlogic and saw Ryan use some gem called Hirb. It looked interesting for sure, so I wrote it down to check it out to completely forget about it.

Until yesterday.

What is Hirb?

A mini view framework for console/irb that's easy to use, even while under its influence. Console goodies include a no-wrap table, auto-pager, tree and menu.

OK. What does that mean?

It improves irb's default output a lot. And by a lot, I mean, A. LOT.

Hirb example

In case you like it, you might want to set it up to autoload in script/console for all your Rails projects. In order to do so, add the following to your ~/.irbrc file:

if ENV['RAILS_ENV']
  require 'rubygems'
  require 'hirb'
  Hirb.enable
end

Resources

Rails model visualization

29 Oct 2009

If you're a developer, you know how it goes. At the beginning of a project, you draw some UML sketches to get you going. There's a nice tool to do that. As your project goes on, and your code grows, these diagrams don't get updated too often. After all, every piece of knowledge must have a single, unambiguous, authoritative representation within a system. And for a class model, that representation is the code.

But at some points during your development, you have to communicate with some stakeholders. They want to know what your class model looks like. So you have to provide them with a drawing. Until recently, we went through the trouble of creating these diagrams manually. But those days are over: we found yUMLmeRails

To get yourself a diagram, follow these steps:

cd your_project
script/plugin install \
    git://github.com/nelsonsilva/yUMLmeRails.git
rake yUMLmeRails:download

Your diagram will be saved in your\project_/diagrams.

Easy. Nice. Handy. Did I mention 'pie' ?

Find or create with hash attributes

04 Sep 2009

Dynamic finders in Rails, represent some the 'magic' we've all gotten used to. One can use these dynamic finders to create or initialize a new object when it doesn't already exist.

# Find a user by screen_name_
user = User.find_by_screen_name("atog")  

# So instead of ...
user = User.find_by_screen_name("atog")  
unless user  
  user = User.create(:name => "atog")  
end

# ... you can  
user = User.find_or_create_by_screen_name("atog")

It gets even better. By passing a hash to the finder you can initialize or create a new object with all the values while only the attribute named in the finder will be used to find the object.

user = User.find_or_create_by_screen_name(
        :screen_name => "atog", 
        :name => "Koen Van der Auwera")

Working with multiple ruby versions - the sequel

28 Aug 2009

Remember when we talked about how to use multiple versions of Ruby on your Mac?

Well, apparently that post is already outdated. Now all you have to do is to install the rvm gem

I've just tried it, and it works without a hickup. I've noticed one little thing: the installation of the gem creates a file ~/.bash_profile. This, apparently, overrides ~/.bashrc on my Mac. I lost all of my neatly-crafted terminal environment. Deleting ~/.bash_profile fixed this. Happy camper!

Present

14 Aug 2009

If this isn't a discovery! I couldn't have said it better myself.

twitter tweet

Just like Nick Quaranto, I prefer positive conditions. For example, you'll find more unless object.blank? in my code than if !object.blank?. So I'm very happy that I learned about present? today.

present?, the inverse of blank?. Heaven.

Working with multiple ruby versions

06 Aug 2009

For a while, I've felt an itch to experiment with Ruby 1.9. It would be better to use it in our day-to-day work, but Ruby 1.9 isn't that far yet. What has hold me back until now, is that I don't want to make an unstable Windows machine out of my Maccie. It's my primary workstation, and I have to work on it constantly.

Via Dr Nic I found Working With Multiple Ruby Versions Has Never Been This Easy.

With the help of the RubySwitcher script, it is laughingly easy to use several Ruby versions next to one another. There's no more excuse not to do it.

Out of the box, you can install and use the following versions of Ruby:

  • install_ruby_191 (install)
    use_ruby_191 (use)
  • install_ruby_186 (install)
    use_ruby_186 (use)
  • install_ruby_187 (install)
    use_ruby_187 (use)
  • install_jruby (install)
    use_jruby (use)
  • install_jruby_120 (install)
    use_jruby_120 (use)
  • install_ree_186 (install)
    use use_ree_186 (use)

To use the standard Ruby version: use_leopard_ruby

i18n and Rails Engines

16 Jun 2009

Rails Engines, what are they? What do they do? But most importantly: how do they do it?

Rails 2.3 brings us much of the same functionality as the Rails Engines plugin. Learn how to embed one application into another in this episode.

Engines allow us to use one application in another in the form of a plugin. As the screencast shows, you can integrate the app folder of a Rails application in the plugin of another one. All models, controllers and views are available. If you still need custom functionality, you can add them in your applications 'own' app folder by redefining the model, controller or view. The same goes for routes; if you have routes.rb in your plugin dir, it is loaded as well.

And i18n, how about that? You would expect config/locals/*.yml to work just as nicely as the app dir and routes.rb. But it doesn't.

Luckily, it's not that hard to solve:

In environment.rb, you add

config.i18n.load_path += Dir[Rails.root.join('vendor', 
    'plugins', 'your_plugin', 'config', 'locales', 
    '*.{rb,yml}')]

If you prefer to read the Railscast: ASCIIcasts - 149: Rails Engines

Generating a timestamp string in Ruby

10 Jun 2009

In the hope that the Google Gods will help me next time I need this :-)

An easy way to generate a human-readable timestamp string, following the ISO 8601 standard, is:

Time.now.utc.iso8601.gsub('-', '').gsub(':', '')

Very handy if you need a timestamp in a file you're writing.

Roleify, a Rails authorization plugin

05 Jun 2009

Today I've pushed a few updates to the Roleify rails plugin.

The changes are

  • you can now use 'namespaced' controllers
  • I added a helper method to hide/show blocks for a specified role

Example

The initializer

Roleify::Role.configure("role_a", "role_b") do
  {
    :role_a => { :dashboard_issues =>  :all },
    :role_b => { :issues => "index" }
  }
end

So, role_a refers to a Dashboard::IssuesController and role_b refers to an IssuesController.

The helper

module ApplicationHelper
  include Roleify::RoleifyableHelper
end

The view

<% allowed?(Roleify::Role::ROLE_A) do %>
  // whatever you want for role_a eyes only
<% end %>

More info on GitHub.

Rails `try`

03 Jun 2009

try is one of those small new additions in the Rails 2.3 release. Luckily I found out about it via a Railscast

What is it?

From the documentation:

Invokes the method identified by the symbol method, passing it any arguments and/or the block specified, just like the regular Ruby Object#send does. Unlike that method however, a NoMethodError exception will not be raised and nil will be returned instead, if the receiving object is a nil object or NilClass.

someobject.try(:some_method)

What did you just say?

The code above normally throws an exception if someobject is nil. By using try it just returns nil.

Don't overuse this.

Using Java 6 with RubyMine on OS X

26 May 2009

What do you need?

Next, open RubyMine’s Info.plist:

mate /Applications/RubyMine\ 1.0.5.app/Contents/Info.plist

Find the line with value 1.5* en change it to 1.6*.

Start RubyMine and check the 'about'. It should look something like this:

RubyMine about screen

Enjoy. It does feel snappier on my side.

On a sidenote: You can set the default Java version via the 'Java Preferences' app.


About this blog

You’re reading Under the Hat, a weblog written by 10to1.

Who’s got the mic?