Source: http://jimneath.org/2008/09/06/multi-model-forms-validations-in-ruby-on-rails/

Background

Say we have 3 models that are all mutually exculise from each other but we need to make sure that all of the models are valid before we save them. The original pplan was to use something similiar to the following:

if @person.save && @cat.save && @dog.save
  // Woohoo!
else
  // Epic fail
end

The problem with this method is: if @person and @dog are valid and save correctly but @dog fails due to validation, then you end up with a person and cat in your database when you don’t want them. This leads to infinite amounts of problems, as rSpec has happily announced on more than one occassion.

The second thing I tried was checking that all the models are valid first then saving them:

if @person.valid? && @cat.valid? && @dog.valid?
  @person.save
  @cat.save
  @dog.save
else
  // Epic fail
end

While this looks good on the controller side, it actually sucks. If person is invalid then the errors are shown on the page as expected, but you don’t to see if any of the other models have any errors because valid? doesn’t get called on them. Aaargh!

The Solution

The View

Did you know you could pass in more than one model to error_messages_for? No, neither did I? What about fields_for? It’s a life saver. Let’s look at an example form for a Person, Cat and a Dog:

<% form_for @person do |f| %>
<%= error_messages_for :object => [@person, @cat, @dog] %>
  <fieldset>
    <legend>Person Details</legend>
    <ol>
      <li>
        <%= f.label :name %>
        <%= f.text_field :name %>
      </li>
    </ol>
  </fieldset>
  <% fields_for :cat do |cat| %>
    <fieldset>
      <legend>Cat Details</legend>
      <ol>
        <li>
          <%= cat.label :breed %>
          <%= cat.text_field :breed %>
        </li>
      </ol>
    </fieldset>
  <% end %>
  <% fields_for :dog do |dog| %>
    <fieldset>
      <legend>Dog Details</legend>
      <ol>
        <li>
          <%= dog.label :breed %>
          <%= dog.text_field :breed %>
        </li>
      </ol>
    </fieldset>
  <% end %>
  <%= f.submit 'Pow!' %>
<% end %>

The main things to look out for here are error_messages_for and fields_for. We pass in an array of the objects we want to display errors for into error_messages_for using :object. This will display all the errors for those models, in our case the person cat and dog errors. Although you need to make sure all the errors for these models are being raised. We’ll look at this later on.

The other thing to take a look at is fields_for. I’ll let the API docs explain this for you:

Creates a scope around a specific model object like form_for, but doesn‘t create the form tags themselves. This makes fields_for suitable for specifying additional model objects in the same form.

So that’s our views done. On to the controller:

The Controller

This is the way we’ve been coping with the problem of validating all the models. I’m sure other people will have other suggestions, but this is what we’re rocking:

def new
  @person = Person.new
  @cat = Cat.new
  @dog = Dog.new
end

def create
  @person = Person.new(params[:person])
  @cat = Cat.new(params[:cat])
  @dog = Dog.new(params[:dog])

  # Run valid? on each model and check for failures
  if [@person, @cat, @dog].all?(&;:valid?)
    Person.transaction do
      @person.save!
      @cat.save!
      @dog.save!
    end
  else
    // Epic fail
  end
end

The only line that you really need to checkout here is the line that runs valid? on each model and check results:

if [@person, @cat, @dog].all?(&;:valid?)

This line runs through each model and runs the valid? method and checks that all the results are true.

As pointed out in the comments, this line could be replaced with:

if @person.valid? & @cat.valid? & @dog.valid?

The Person.transaction block makes sure that if one of the models fails to save then the other models aren’t saved as well. This stops you ending up with random saved models that shouldn’t be there.

Bosh.

Advertisements

Source: http://jimneath.org/2008/11/22/escaping-params-containing-periods/

Just a quick one. Say you have a route like the following:

map.resources :users

And you’re using email addresses to look up users like:

/users/jim@somewhere.com

You’re going to run into an error along the lines of:

Missing template users/show.com.erb in view path blah/app/views

Which obviously isn’t what you want. To fix this, change your route to the following:

map.resources :users, :requirements => { :id => /.*/ }

Rejoice.

Source: http://jimneath.org/2009/02/16/creating-pdf-documents-in-ruby-on-rails/

Those of you that follow me on Twitter will probably know that I’ve spent the last week or so trying to find a decent way of generating PDF documents from a Rails application. I finally found a solution that suited my needs so I thought I’d share it with you lovely people.

Initial Probing

After my first round of googling I came across 2 solutions that people seem to be using:

I’ll admit I didn’t really look too much into PDF::Writer but I did spend a couple of days playing around with Prawn.

All was going well until I ran into certain situations. The two main problems I had with Prawn were that it’s too difficult to style things as I wanted to and generating a table of contents. I might be missing something but I couldn’t get my head around how to solve the latter.

I don’t want to learn a new syntax to define my PDF documents. I don’t want to learn a new way of styling things. I like my HTML and CSS.

WHERE’S MY HTML AND CSS?!

Introducing Prince

Prince XML is a command line program that takes your spiffy html and css and returns a nicely formatted PDF document for you.

Prince is a computer program that converts XML and HTML into PDF documents. Prince can read many XML formats, including XHTML and SVG. Prince formats documents according to style sheets written in CSS.

See, I told you.

So, we’ve got prince xml, but what about hooking it up with rails?

Introducing Princely

Princely is a fantastic plugin by Michael Bleigh, author of other great plugins, such as subdomain-fu and acts-as-taggable-on.

Princely is basically a wrapper around the Prince API. It allows you to define your PDF views as templates like show.pdf.erb. You can write your views as you would normal html views and Princely will return a pdf when you hit those pages.

def show
  respond_to do |format|
    format.html
    format.pdf do
      render :pdf => "filename", :stylesheets => ["application", "prince"], :layout => "pdf"
    end
  end
end

Awesome, right?

Installing Prince and Princely

To install Prince XML, visit the download page and chose the package which suits your needs. Done.

Next, to install Princely, run the following command from your Rails app.

script/plugin install git://github.com/mbleigh/princely.git

Page Numbering

To set the page numbers of you PDFs you’ll need to use the counter attribute of CSS3.

@page {
  @bottom-left {
    content: counter(page);
  }
}

This snippet of code will, funnily enough, add the current page number to the bottom left of each page. That’s all there is to it.

If you’d prefer to show the page number along with the total number of pages, you can use the following:

@page {
  @bottom-left {
    content: "Page " counter(page) " of " counter(pages);
  }
}

Table of Contents

If you’re creating a large PDF with a few sections, it’s generally a good idea to include a table of contents at the start of your document.

The first thing you need to do, is output a list of links at the start of you document that link to internal anchors:

<ul id="toc">
  <li><a href="#ruby">Chapter 1: An Introduction to Ruby</a></li>
  <li><a href="#rails">Chapter 2: Hello, Rails!</a></li>
  <li><a href="#prince">Chapter 3: Pump it up, Prince!</a></li>
</ul>

This will give you a list, that looks something along the lines of the following image:

toc

Now with a bit of CSS magic, we can add the page numbers from our PDF to the table of contents. Ready for this? Go!

ul#toc a::after
{
  content: leader('.') target-counter(attr(href), page);
}

That’s it. attr(href) finds the target of the link. target-counter finds the page that the anchor is on and the leader call just pads the left had side with periods. Win.

That nifty bit of CSS should leave you with something looking like this:

toc unstyled

A bit more CSS to tidy it up a bit:

ul#toc ul {
	margin: 0;
	list-style: none;
	padding: 0;
}

ul#toc a {
	text-decoration: none;
}

ul#toc li {
	margin: 0;
	padding: 0;
	list-style: none;
}

And then we should have something that looks a bit nicer:

toc styled

That’s all there is to it. Easy, right?

Metadata

Prince writes metadata to your PDFs via the meta tags in your html. You can set the document author, subject and keywords using the following:

<head>
  <title>PDF Generation</title>
  <meta name="author" content="Jim Neath"/>
  <meta name="subject" content="Generating PDFs with Prince"/>
  <meta name="keywords" content="PDF, prince, ruby, rails"/>
</head>

Further Reading

Magic Model Generator

Tháng Ba 26, 2009

Dr Nic is a great guy :)

Source: http://magicmodels.rubyforge.org/magic_model_generator/

./script/generate magic_model

What

Imagine you get offered $5,000 to write a basic website/admin application on a legacy database that has 200 interconnected tables. You’ll need to add all the associations and validations based on the existing schema.

Imagine how long that would take! 1 day? 1 week? more?

Try 1 minute.

The Magic Model Generator does all this for you automatically.

Installing

$ sudo gem install magic_model_generator

Quick demo

Create a rails application, and point it to your database.

$ rails magic_show -d [mysql|sqlite|postgresql|oracle|etc|etc]
$ cd magic_show
$ cp database.yml.sample database.yml
and point it to your database.yml to your legacy database

In the video below I use the database created for the ActiveRecord test cases – activerecord_unittest. If you’ve never downloaded the activerecord gem, run:

$ rake build_[mysql|sqlite|postgresql|oracle|etc|etc]_databases
$ rake test_[mysql|sqlite|postgresql|oracle|etc|etc]

Now install the magic_model_generator gem:

$ sudo gem install magic_model_generator

By the way, that’s all the preparation I did for the video.

Now recreate the schema.rb file and the schema_info database table via

$ rake db:migrate

.

Finally, run the generator:

$ ./script/generate magic_model

Coming

Currently rails_generators cannot merge results into existing files, only skip or overwrite. I am investigating a fix for this so that you can use the MMG for iterative development.

Related articles

  • Original release at RejectConf –

Similar ideas

Câu chuyện bát mì

Tháng Ba 8, 2009

Trong cuộc sống ngày nay, xin đừng quên rằng còn tồn tại lòng nhân ái. Đây là một câu chuyện có thật, chúng tôi gọi là “Câu chuyện bát mì”.Chuyện xảy ra cách đây năm mươi năm vào ngày 31/12, một ngày cuối năm tại quán mì Bắc Hải Đình, đường Trát Hoảng, Nhật Bản.
o O o
Đêm giao thừa, ăn mì sợi đón năm mới là phong tục tập quán của người Nhật, cho đến ngày đó công việc làm ăn của quán mì rất phát đạt. Ngày thường, đến chạng vạng tối trên đường phố hãy còn tấp nập ồn ào nhưng vào ngày này mọi người đều lo về nhà sớm hơn một chút để kịp đón năm mới. Vì vậy đường phố trong phút chốc đã trở nên vắng vẻ.
Ông chủ Bắc Hải Đình là một người thật thà chất phát, còn bà chủ là một người nhiệt tình, tiếp đãi khách như người thân. Đêm giao thừa, khi bà chủ định đóng cửa thì cánh cửa bị mở ra nhè nhẹ, một người phụ nữ trung niên dẫn theo hai bé trai bước vào. đứa nhỏ khoảng sáu tuổi, đứa lớn khoảng 10 tuổi. Hai đứa mặc đồ thể thao giống nhau, còn người phụ nữ mặc cái áo khoác ngoài lỗi thời.
– Xin mời ngồi!
Nghe bà chủ mời, người phụ nữ rụt rè nói:
– Có thể… cho tôi một… bát mì được không?
Phía sau người phụ nữ, hai đứa bé đang nhìn chăm chú.
– Đương nhiên… đương nhiên là được, mời ngồi vào đây.
Bà chủ dắt họ vào bàn số hai, sau đó quay vào bếp gọi to:
– Cho một bát mì.
Ba mẹ con ngồi ăn chung một bát mì trông rất ngon lành, họ vừa ăn vừa trò chuyện khe khẽ với nhau. “Ngon quá” – thằng anh nói.
– Mẹ, mẹ ăn thử đi – thằng em vừa nói vừa gắp mì đưa vào miệng mẹ.
Sau khi ăn xong, người phụ nữ trả một trăm năm mươi đồng. Ba mẹ con cùng khen: “Thật là ngon ! Cám ơn !” rồi cúi chào và bước ra khỏi quán.
– Cám ơn các vị ! Chúc năm mới vui vẻ – ông bà chủ cùng nói.
Công việc hàng ngày bận rộn, thế mà đã trôi qua một năm. Lại đến ngày 31/12, ngày chuẩn bị đón năm mới. Công việc của Bắc Hải Đình vẫn phát đạt. So với năm ngoái, năm nay có vẻ bận rộn hơn. Hơn mười giờ, bà chủ toan đóng cửa thì cánh cửa lại bị mở ra nhè nhẹ. Bước vào tiệm là một người phụ nữ dẫn theo hai đứa trẻ. Bà chủ nhìn thấy cái áo khoác lỗi thời liền nhớ lại vị khách hàng cuối cùng năm ngoái.
– Có thể… cho tôi một… bát mì được không?
– Đương nhiên… đương nhiên, mời ngồi!
Bà chủ lại đưa họ đến bàn số hai như năm ngoái, vừa nói vọng vào bếp:
– Cho một bát mì.
Ông chủ nghe xong liền nhanh tay cho thêm củi vào bếp trả lời:
– Vâng, một bát mì!
Bà chủ vào trong nói nhỏ với chồng:
– Này ông, mình nấu cho họ ba bát mì được không?
– Không được đâu, nếu mình làm thế chắc họ sẽ không vừa ý.
Ông chủ trả lời thế nhưng lại bỏ nhiều mì vào nồi nước lèo, ông ta cười cười nhìn vợ và thầm nghĩ: “Trông bà bề ngoài khô khan nhưng lòng dạ cũng không đến nỗi nào!”
Ông làm một tô mì to thơm phức đưa cho bà vợ bưng ra. Ba mẹ con ngồi quanh bát mì vừa ăn vừa thảo luận. Những lời nói của họ đều lọt vào tai hai vợ chồng ông chủ quán.
– Thơm quá!
– Năm nay vẫn được đến Bắc Hải Đình ăn mì thật là may mắn quá!
– Sang năm nếu được đến đây nữa thì tốt biết mấy!
Ăn xong, trả một trăm năm mươi đồng, ba mẹ con ra khỏi tiệm Bắc Hải Đình.
– Cám ơn các vị! Chúc năm mới vui vẻ!
Nhìn theo bóng dáng ba mẹ con, hai vợ chồng chủ quán thảo luận với nhau một lúc lâu.
Đến ngày 31/12 lần thứ ba, công việc làm ăn của Bắc Hải Đình vẫn rất tốt, vợ chồng ông chủ quán bận rộn đến nỗi không có thời gian nói chuyện. Đến 9g30 tối, cả hai người đều cảm thấy trong lòng có một cảm giác gì đó khó tả. Đến 10 giờ, nhân viên trong tiệm đều đã nhận bao lì xì và ra về. Ông chủ vội vã tháo các tấm bảng trên tường ghi giá tiền của năm nay là “200đ/bát mì” và thay vào đó giá của năm ngoái “150đ/bát mì”. Trên bàn số hai, ba mươi phút trước bà chủ đã đặt một tờ giấy “Đã đặt chỗ”. Đúng 10g30, ba mẹ con xuất hiện, hình như họ cố chờ khách ra về hết rồi mới đến. Đứa con trai lớn mặc bộ quần áo đồng phục cấp hai, đứa em mặc bộ quần áo của anh, nó hơi rộng một chút, cả hai đứa đêu đã lớn rất nhiều.
– Mời vào! Mời vào! – bà chủ nhiệt tình chào đón.
Nhìn thấy khuôn mặt tươi cười của bà chủ, người mẹ chậm rãi nói:
– Làm ơn nấu cho chúng tôi…hai bát mì được không?
– Được chứ, mời ngồi bên này!
Bà chủ lại đưa họ đến bàn số hai, nhanh tay cất tờ giấy “Đã đặt chỗ” đi, sau đó quay vào trong la to: “Hai bát mì”
– Vâng, hai bát mì. Có ngay.
Ông chủ vừa nói vừa bỏ ba phần mì vào nồi.
Ba mẹ con vừa ăn vừa trò chuyện, dáng vẻ rất phấn khởi. Đứng sau bếp, vợ chồng ông chủ cũng cảm nhận được sự vui mừng của ba mẹ con, trong lòng họ cũng cảm thấy vui lây.
– Tiểu Thuần và anh lớn này, hôm nay mẹ muốn cảm ơn các con!
– Cảm ơn chúng con? Tại sao ạ?
– Chuyện là thế này: vụ tai nạn xe hơi của bố các con đã làm cho tám người bị thương, công ty bảo hiểm chỉ bồi thường một phần, phần còn lại chúng ta phải chịu, vì vậy mấy năm nay mỗi tháng chúng ta đều phải nộp năm mươi ngàn đồng.
– Chuyện đó thì chúng con biết rồi – đứa con lớn trả lời.
Bà chủ đứng bên trong không dám động đậy để lắng nghe.
– Lẽ ra phải đến tháng ba năm sau chúng ta mới nộp hết nhưng năm nay mẹ đã nộp xong cả rồi!
– Hả, mẹ nói thật đấy chứ?
– Ừ, mẹ nói thật. Bởi vì anh lớn nhận trách nhiệm đi đưa báo, còn Tiểu Thuần giúp mẹ đi chợ nấu cơm làm mẹ có thể yên tâm làm việc, công ty đã phát cho mẹ một tháng lương đặc biệt, vì vậy số tiền chúng ta còn thiếu mẹ đã nộp hết rồi.
– Mẹ ơi! Anh ơi! Thật là tốt quá, nhưng sau này mẹ cứ để con tiếp tục nấu cơm nhé.
– Con cũng tiếp tục đi đưa báo. Tiểu Thuần chúng ta phải cố gắng lên!
– Mẹ cám ơn hai anh em con nhiều!
– Tiểu Thuần và con có một bí mật chưa nói cho mẹ biết. Đó là vào một ngày chủ nhật của tháng mười một, trường của Tiểu Thuần gửi thư mời phụ huynh đến dự một tiết học. Thầy giáo của Tiểu Thuần còn gửi một bức thư đặc biệt cho biết bài văn của Tiểu Thuần đã được chọn làm đại diện cho Bắc Hải đảo đi dự thi văn toàn quốc. Con nghe bạn của Tiểu Thuần nói mới biết nên hôm đó con đã thay mẹ đến dự.
– Có thật thế không? Sau đó ra sao?
– Thầy giáo ra đề bài: “Chí hướng và nguyện vọng của em là gì?” Tiểu Thuần đã lấy đề tài bát mì để viết và được đọc trước tập thể nữa chứ. Bài văn được viết như sau: “Ba bị tai nạn xe mất đi để lại nhiều gánh nặng. Để gánh vác trách nhiệm này, mẹ phải thức khuya dậy sớm để làm việc”. Đến cả việc hàng ngày con phải đi đưa báo, em cũng viết vào bài nữa. Lại còn: “Vào tối 31/12, ba mẹ con cùng ăn một bát mì rất ngon. Ba người chỉ gọi một tô mì, nhưng hai vợ chồng bác chủ tiệm vẫn cám ơn và còn chúc chúng tôi năm mới vui vẻ nữa. Lời chúc đó đã giúp chúng tôi có dũng khí để sống, khiến cho gánh nặng của ba để lại nhẹ nhàng hơn”. Vì vậy Tiểu Thuần viết rằng nguyện vọng của nó là sau này mở một tiệm mì, trở thành ông chủ tiệm mì lớn nhất ở Nhật Bản, cũng sẽ nói với khách hàng của mình những câu như: “Cố gắng lên ! Chúc hạnh phúc ! Cám ơn !”
Đứng sau bếp, hai vợ chồng chủ quán lặng người lắng nghe ba mẹ con nói chuyện mà nước mắt lăn dài.
– Bài văn đọc xong, thầy giáo nói: anh của Tiểu Thuần hôm nay thay mẹ đến dự, mời em lên phát biểu vài lời.
– Thật thế à? Thế lúc đó con nói sao?
– Bởi vì quá bất ngờ nên lúc đầu con không biết phải nói gì cả, con nói: “Cám ơn sự quan tâm và thương yêu của thầy cô đối với Tiểu Thuần. Hàng ngày em con phải đi chợ nấu cơm nên mỗi khi tham gian hoạt động đoàn thể gì đó nó đều phải vội vả về nhà, điều này gây không ít phiền toái cho mọi người. Vừa rồi khi em con đọc bài văn thì trong lòng con cảm thấy sự xấu hổ nhưng đó là sự xấu hổ chân chính. Mấy năm nay mẹ chỉ gọi một bát mì, đó là cả một sự dũng cảm. Anh em chúng con không bao giờ quên được… Anh em con tự hứa sẽ cố gắng hơn nữa, quan tâm chăm sóc mẹ nhiều hơn. Cuối cùng con nhờ các thầy cô quan tâm giúp đỡ cho em con.”
Ba mẹ con nắm tay nhau, vỗ vai động viên nhau, vui vẻ cùng nhau ăn hết tô mì đón năm mới rồi trả 300 đồng, nói câu cám ơn vợ chồng chủ quán, cúi chào và ra về. Nhìn theo ba mẹ con, vợ chồng ông chủ quán nói với theo:
– Cám ơn! Chúc mừng năm mới!
Lại một năm nữa trôi qua.
Bắc Hải Đình vào lúc 9g tối, bàn số hai được đặt một tấm giấy “Đã đặt chỗ” nhưng ba mẹ con vẫn không thấy xuất hiện.
Năm thứ hai rồi thứ ba, bàn số hai vẫn không có người ngồi. Ba mẹ con vẫn không thấy trở lại. Việc làm ăn của Bắc Hải Đình vẫn như mọi năm, toàn bộ đồ đạc trong tiệm được thay đổi, bàn ghế được thay mới nhưng bàn số hai thì được giữ lại y như cũ.
“Việc này có ý nghĩa như thế nào?” Nhiều người khách cảm thấy ngạc nhiên khi nhìn thấy cảnh này nên đã hỏi. Ông bà chủ liền kể lại câu chuyện bát mì cho mọi người nghe. Cái bàn cũ kia được đặt ngay chính giữa, đó cũng là một sự hy vọng một ngày nào đó ba vị khách kia sẽ quay trở lại, cái bàn này sẽ dùng để tiếp đón họ. Bàn số hai “cũ” trở thành “cái bàn hạnh phúc”, mọi người đều muốn thử ngồi vào cái bàn này.
Rồi rất nhiều lần 31/12 đã đi qua.
Lại một ngày 31/12 đến. Các chủ tiệm lân cận Bắc Hải Đình sau khi đóng cửa đều dắt người nhà đến Bắc Hải Đình ăn mì. Họ vừa ăn vừa chờ tiếng chuông giao thừa vang lên. Sau đó, mọi người đi bái thần, đây là thói quen năm, sáu năm nay. Hơn 9g30 tối, trước tiên vợ chồng ông chủ tiệm cá đem đến một chậu cá còn sống. Tiếp đó, những người khác đem đến nào là rượu, thức ăn, chẳng mấy chốc đã có khoảng ba, bốn chục người. Mọi người rất vui vẻ. Ai cũng biết lai lịch của bàn số hai. Không ai nói ra nhưng thâm tâm họ đang mong chờ giây phút đón mừng năm mới. Người thì ăn mì, người thì uống rượu, người bận rộn chuẩn bị thức ăn… Mọi người vừa ăn, vừa trò chuyện, từ chuyện trên trời dưới đất đến chuyện nhà bên có thêm một chú nhóc nữa. Chuyện gì cũng tạo thành một chuỗi câu chuyện vui vẻ. Ở đây ai cũng coi nhau như người nhà.
Đến 10g30, cửa tiệm bỗng nhiên mở ra nhè nhẹ, mọi người trong tiệm liền im bặt và nhìn ra cửa. Hai thanh niên mặc veston, tay cầm áo khoác bước vào, mọi người trong quán thở phào và không khí ồn ào náo nhiệt trở lại. Bà chủ định ra nói lời xin lỗi khách vì quán đã hết chỗ thì đúng lúc đó một người phụ nữ ăn mặc hợp thời trang bước vào, đứng giữa hai thanh niên.
Mọi người trong tiệm dường như nín thở khi nghe người phụ nữ ấy nói chầm chậm:
– Làm ơn… làm ơn cho chúng tôi ba bát mì được không?
Gương mặt bà chủ chợt biến sắc. Đã mười mấy năm rồi, hình ảnh bà mẹ trẻ cùng hai đứa con trai chợt hiện về và bây giờ họ đang đứng trước mặt bà đây. Đứng sau bếp, ông chủ như mụ người đi, giơ tay chỉ vào ba người khách, lắp lắp nói:
– Các vị… các vị là…
Một trong hai thanh niên tiếp lời:
-Vâng! Vào ngày cuối năm của mười bốn năm trước đây, ba mẹ con cháu đã gọi một bát mì, nhận được sự khích lệ của bát mì đó, ba mẹ con cháu như có thêm nghị lức để sống. Sau đó, ba mẹ con cháu đã chuyển đến sống ở nhà ông bà ngoại ở Tư Hạ. Năm nay cháu thi đỗ vào trường y, hiện đang thực tập tại khoa nhi của bệnh viện Kinh Đô. Tháng tư năm sau cháu sẽ đến phục vụ tại bệnh viện tổng hợp của Trát Hoảng. Hôm nay, chúng cháu trước là đến chào hỏi bệnh viện, thuận đường ghé thăm mộ của ba chúng cháu. Còn em cháu mơ ước trở thành ông chủ tiệm mì lớn nhất Nhật Bản không thành, hiện đang là nhân viên của Ngân hàng Kinh Đô. Cuối cùng, ý định nung nấy từ bao lâu nay của chúng cháu là hôm nay, ba mẹ con cháu muốn đến chào hỏi hai bác và ăn mì ở Bắc Hải Đình này.
Ông bà chủ quán vừa nghe vừa gật đầu mà nước mắt ướt đẫm mặt. Ông chủ tiệm rau ngồi gần cửa ra vào đang ăn đầy miệng mì, vội vả nhả ra, đứng dậy nói:
– Này, ông bà chủ, sao lại thế này? Không phải là ông bà đã chuẩn bị cả mười năm nay để có ngày gặp mặt này đó sao ? Mau tiếp khách đi chứ. Mau lên!
Bà chủ như bừng tỉnh giấc, đập vào vai ông hàng rau, cười nói:
– Ồ phải… Xin mời! Xin mời! Nào bàn số hai cho ba bát mì.
Ông chủ vội vàng lau nước mắt trả lời:
– Có ngay. Ba bát mì.
o O o
Thật ra cái mà ông bà chủ tiệm bỏ ra không có gì nhiều lắm, chỉ là vài vắt mì, vài câu nói chân thành mang tính khích lệ, động viên chúc mừng. Với xã hội năng động ngày nay, con người dường như có một chút gì đó lạnh lùng, nhẫn tâm. Nhưng từ câu chuyện này, tôi đi đến kết luận rằng : chúng ta không nên chịu ảnh hưởng của hoàn cảnh xung quanh, chỉ cần bạn có một chút quan tâm dành cho người khác thì bạn có thể đem đến niềm hạnh phúc cho họ rồi. Chúng ta không nên nhỏ nhoi ích kỷ bởi tôi tin trong mỗi chúng ta đều ẩn chứa một tấm lòng nhân ái. Hãy mở kho tàng ấy ra và thắp sáng nó lên dù chỉ là một chút ánh sáng yếu ớt ,nhưng trong đêm đông giá rét thì nó có thể mang lại sự ấm áp cho mọi người.

Source: http://www.hokstad.com/ruby-object-model.html

Suggested reading

The Ruby object model can make you go insane. _why has a great article that illuminates the particular hairy beast that is meta classes. You should read it.

Ruby Objects

Conceptually, Ruby objects consists of the following:

  • A reference to the objects immediate class – the MRI interpreter stores this in a field named “klass” and you may see the term “klass” show up in Ruby-land a lot for that reason. For an object that has an meta-class this is a pointer to the meta-class
  • A hash table of instance variables
  • A set of flags (taint etc.)

MRI “cheats” in that objects of the built-in classes Class, Float, Bignum,Struct, String, Array, Regexp, Hash and File are not real Ruby objects: They don’t have the hash table of instance variables. Instead they have a fixed structure. You can still set instance variables for these objects, but behind the scenes MRI 1.8.x at least will then create an instance variable hash table and store that hash table in a hash mapping from the object. This saves a little bit of space if (as is usually the case) most objects of these built in classes don’t have instance variables besides the “hardcoded” ones – for small objects like Float in particular this can be a significant saving.

(The following is updated per comment from Rick DeNatale below:)

For some other classes, there’s not even a pointer. MRI takes advantage of the fact that there are certain values the object pointer won’t take. When MRI determines the class of an “object” it follows the following procedure:

  • If the least significant bit (bit 0) is set to 1, the object is a Fixnum. This works since the object pointer will point to an address that’s aligned in memory, and so never will have bit 0 set.
  • If the value matches 0, it’s class is FalseClass, 2 = TrueClass, 4 = NilClass, 6 = undefined.
  • If the lowest byte of the value matches 0x0e, it’s a Symbol, and the Symbol is determined from the top 3 bytes.

This use of part of the value to indicate type is often called a “type tag” – some language environments will use more bits or more complicated schemes to avoid having to allocate full objects.

Ruby Classes

There are two types of Ruby classes:

  • “Real” classes.
  • Meta-classes or “eigenclasses” as they are often called. MRI also refers to them as “virtual” classes.

A meta-class is for all practical purposes an actual class. It is an object of type Class. The only thing “special” about a meta-class is that it is created as needed and inserted in the inheritance chain before the objects “real” class. So inside the MRI interpreter object->klass can refer to a meta-class, that has a pointer named “super” that refers to the next class in the chain. When you call object.class in MRI, the interpreter actually “skips” over the meta-class (and modules) if it’s there.

The diagram below shows the actual inheritance of Object, Module and Class in MRI as visible from C. If this doesn’t make sense to you, read the section on #send below, but particularly keep in mind that:

  • Classes are objects. So they are also instances of another class.
  • A class object is NOT an instance of it’s superclass. [some class object].class denotes “instance of”, [some class object].superclass denotes “inherits from”.
  • To find out which method implementation is called for any object, you go “out and up”. That is, you find the objects “klass”, and then follow the “super” chain up until you find a matching method. This gets confusing for classes because they are also objects: You do NOT follow super for the first step for classes – they behave exactly like objects.

In the diagram below, “normal” classes are green, and meta-classes are blue. The dashed lines represent “instance off” (the “klass” pointer), and the solid lines represent “inherits” (the “super” method):

So, for example, when sending a message to the object Class, you step out, to the meta class “Class” (in blue), and look for it there, if you don’t find it, you follow the solid arrows until you do. This in turn will get you: the Module meta class, the Object meta class, Class, Module, Object, Kernel (since classes in Ruby are open, you might also find someone has reopened the class and caused additional modules etc. to get inserted into the inheritance chain).

Because Ruby’s #class method skips metaclasses, you will get “Class” returned if you do Class.class – it’s following the same chain as above, but skipping the blue boxes (and any included Module’s)

To explore the class/metaclass inheritance in Ruby, you can use this minimal extension to see what values MRI actually operates on:

#include "ruby.h"

VALUE real_super(VALUE self) {
  return RCLASS(self)->super;
}

VALUE real_klass(VALUE self) {
  return RBASIC(self)->klass;
}

void Init_inheritance() {
  rb_define_method(rb_cClass,"real_super",real_super,0);
  rb_define_method(rb_cClass,"real_klass",real_klass,0);
}

Put the above in “inheritance.c” and create extconf.rb:

require 'mkmf'

extension_name = 'inheritance'
dir_config(extension_name)
create_makefile(extension_name)

To use it do “ruby extconf.rb ; make”, and then:

require 'inheritance'

p Object.real_klass
p Object.real_super

Conceptually a Class object consist of:

  • A reference to the objects immediate class (as for a “real” Ruby object) – this would normally be the class “Class”
  • A set of flags (taint etc.)
  • A hash table of instance variables (for the class)
  • A hash table of methods
  • A reference to the superclass, i.e. the class this class has inherited from.

Ruby Modules


A Ruby Module is an object that acts as a placeholder for methods and constants. Module is actually the superclass of Class. The main distinction is that you can’t create instances of a module, but you can (obviously) create instances of a class.

Internally in MRI the structure of a Module and Class objects is the same.

Taint, Frozen and other flags

MRI defines the following flags for an object:

  • Singleton
  • Mark
  • Finalize
  • Taint
  • Exivar
  • Freeze
  • A number of “user” flags.

“Singleton” is set on objects of type Class that are meta-classes.

Mark and Finalize are used by the garbage collector. “Taint” is used for the “taint mode” – depending on the security level, some objects may be marked as “tainted” and thus unsafe, and certain operations may be disallowed.

“Exivar” is used for objects of the “fake” builtin classes to indicate that this instance has an external instance variable hash table that must be looked up elsewhere.

“Freeze” prevents an object from being modified.

Of these, only Singleton, Taint and Freeze represent behavior that are “observable” from inside Ruby, as opposed to when delving under the hood of MRI.

Send

Send is perhaps the most vital concept in the Ruby object model beyond classes and objects. Almost all actions in Ruby at least conceptually boils down to sending a message to an object.

Send operates roughly like this (lots of details omitted):

  • Identify the class to start at. “Objects” of class Fixnum are treated specially since they’re not actually objects at all. nil, true and false are also special cased. For other objects this means grabbing the “klass” pointer.
  • The method cache is checked, to avoid complex lookups of the method on repeated calls.
  • If not in the method cache, the method is searched for. This is done by lookup up the method in the “klass”, and if not found replace “klass” with “klass->super” and try again, until the top of the inheritance chain is found (in which case the method doesn’t exist). The result is put in the cache.
  • If the method is not found, method_missing is called in roughly the same way.
  • private/protected access checks are carried out
  • Access checks are done in case the safe level is set to trigger exceptions for unsafe operations.
  • The arguments are prepared
  • A “stack frame” is prepared – MRI maintains it’s own “Ruby stack”
  • If the method is a C function various special setup is done.
  • If the method is an attribute getter/setter (attr_accessor/attr_read/attr_write), the appropriate built in MRI functions are called rather than executing a method body. Same with methods consisting of “super”
  • The method is finally called.

This makes MRI method calls extremely expensive. The method cache alleviates some of it, but the remaining work still has a huge cost compared to C++ for example, where the worst case runtime overhead is a virtual method in a multiple-inherited class, which consists of an indirect pointer lookup and a call to a “thunk” function that fixes up the object pointer (a couple of instructions at most) so the method can access the right data, and jumps to the real method, and the typical cost is an indirect pointer lookup and a call instruction. Some of this overhead is avoidable in a more streamlined implementation, but quite a bit of it is extremely hard or impossible to get rid of within the required semantics of Ruby.

method_missing

In MRI, relying on method_missing is even more expensive than #send, as the method first needs to be looked up and then method_missing itself causes another looup, but the method cache makes it a reasonable choice for dynamically “adding” methods to objects as “send” is short-circuited early in loops etc., so after the first call the cost is fairly low. A brief benchmarks surprisingly shows that defining a new method using #define_method is actually slower than relying on method_missing. Here’s the benchmark:

#!/bin/env ruby                                                                                                                                            

require 'benchmark'

class Foo
  def test1
  end

  def method_missing sym
    if sym == :test2
    end
  end
end

Foo.class_eval do
  define_method :test3 do
  end
end

n = 1000000
f = Foo.new
Benchmark.bmbm(20) do |x|
  x.report("test1") { n.times { f.test1 } }
  x.report("test2 (method_missing)")  { n.times { f.test2 } }
  x.report("test3 (define method)") { n.times { f.test3 } }
end

And here are the results from one of my machines:

$ ruby send_vs_method_missing.rb 
Rehearsal ----------------------------------------------------------
test1                    1.390000   0.390000   1.780000 (  1.788041)
test2 (method_missing)   1.660000   0.460000   2.120000 (  2.626747)
test3 (define method)    1.880000   0.450000   2.330000 (  2.326830)
------------------------------------------------- total: 6.230000sec

                             user     system      total        real
test1                    1.320000   0.450000   1.770000 (  1.777432)
test2 (method_missing)   1.660000   0.480000   2.140000 (  2.124609)
test3 (define method)    1.870000   0.450000   2.320000 (  2.326343)

How to speed up gem installs

Tháng Ba 8, 2009

Answer: Turn off ri and rdoc installation. Sure, you can do this on the commandline, like so:

sudo gem install fastercsv --no-ri --no-rdoc

Better, though, is to set this up as the default in your ~/.gemrc file.

---
:verbose: true
:sources:
- http://gems.rubyforge.org/
- http://gems.github.com/
:update_sources: true
:backtrace: false
:bulk_threshold: 1000
:benchmark: false
gem: --no-ri --no-rdoc

Just add that last line and your gem installations will complete in no time.

Sometimes it’s the smaller, throwaway tips that can really brighten your day.

Select a Reject

Tháng Ba 3, 2009

Source: http://errtheblog.com/posts/44-select-a-reject

Hey: Ruby is expressive. Super expressive. There are many methods which roll up repetitive tasks right there in the core classes. Let’s examine two some.

Enumerable#select (and #detect)

Say I have an array of ActiveRecord objects and I want to find all the objects for which book_type is Comic (as opposed to Novel). And I only want to call AR’s find once.

books  = Book.find(:all, :order => 'id desc', :limit => 20)
comics = []
books.each do |book|
  comics << book if book.item_type == 'Comic'
end

Okay, that’s one way. I could also use inject. Or, I could just use select:

books  = Book.find(:all, :order => 'id desc', :limit => 20)
comics = books.select { |i| i.item_type == 'Comic' }

Basically, select will gather any objects for which the block you pass it evaluates to true.

Very calm, very collected.

Use detect if you only want the first match:

books = Book.find(:all, :order => 'id desc', :limit => 20)
first_comic = books.detect { |i| i.item_type == 'Comic' }

Enumerable#select (and #detect) sometimes lies

Here’s the catch: select doesn’t work so well on hashes. Check this out:

>> blogs = { :nubyonrails => true, :err => false, :slash7 => true }
=> {:err=>false, :nubyonrails=>true, :slash7=>true}
>> blogs.select { |blog, worth_reading| worth_reading }
=> [[:nubyonrails, true], [:slash7, true]]

See? We got back an array of arrays when what we wanted was a hash. That complicates things a bit. One soluton is to use Hash[], as mentioned previously in the Hash Fun edition of Err.

>> keepers = blogs.select { |blog, worth_reading| worth_reading }
=> [[:nubyonrails, true], [:slash7, true]]
>> Hash[*keepers.flatten]
=> {:nubyonrails=>true, :slash7=>true}

That’s kind of weak, though. Hard to remember and ‘twill break if you have nested arrays. So let’s add onto Hash a nested array safe version:

class Array
  def to_hash
    Hash[*inject([]) { |array, (key, value)| array + [key, value] }]
  end
  alias :to_h :to_hash
end

class Hash
  def select(&block)
    super(&block).to_hash
  end
end

And now:

>> keepers = blogs.select { |blog, worth_reading| worth_reading }
=> {:nubyonrails=>true, :slash7=>true}

Too much magic? Way too much. I don’t really like overriding core methods. Sure, we could use hash_select or something, but there must be a simpler solution?

There is. Just double negate. Namely, Enumerable#reject.

Enumerable#reject

For some reason the reject method works just like you’d want it to (with hashes). You pass it a block and it returns all the elements which evaluate to false. That is, it rejects any elements for which the block evaluates to true. Using our previous example, let’s play:

>> blogs = { :nubyonrails => true, :err => false, :slash7 => true }
=> {:err=>false, :nubyonrails=>true, :slash7=>true}
>> keepers = blogs.reject { |blog, worth_reading| not worth_reading  }
=> {:nubyonrails=>true, :slash7=>true}

No tricky metaprogramming. No overriding default methods. reject just works. It’s almost the opposite of select, with a little bit more class.

The Real World

Got a range of numbers and only want to find the even ones? Easy, with select:

>> (0..10).select { |n| n % 2 == 0 } 
=> [0, 2, 4, 6, 8, 10]

Have a bunch of files/directories and only want to find files, not directories?

>> Dir['*/*'].reject { |f| File.directory? f }
=> ["pedalists/Rakefile", "pedalists/README"]

In some of my code I keep a list of recent stories and display them in a sidebar. I don’t want to display the story you’re viewing in the sidebar, though. Hey, reject! (which modifies the receiver in place):

recent_stories.reject! { |i| i.id == @story.id } if @story

That’s it.

The Enumerable mixin contains much goodness we hardly ever talk about. Check it out. Just, tread lightly.