Fri 30 January, 2009

add to del.icio.us. look up in del.icio.us.
add to furlThu 29 January, 2009

Monkeybars has a Kenai project now.
The code is staying at gitorius, but with Kenai we get some extras, such as a wiki, which is shaping up quite rapidly.
Also, InfoQ has an interview with me about Monkeybars reaching 1.0
add to del.icio.us. look up in del.icio.us.
add to furl
When the economy hits a downturn this typically has an immediate effect on tech conferences. Many tech conferences cannot run successfully without sponsorships, and with companies becoming more conservative with spending the marketing budget is usually the first item to get cut.
So yet another way you can help Ruby and Rails Activism is by attending (supporting) a conference. Below you’ll find conferences coming up in the next 6 months. If you think I’ve missed one, or if the information is incorrect, please post a comment.
February 6-7 – Acts As Conference in Orlando, Florida
Cost: $125
February 19-21 – RubyRx in Durham, North Carolina
Cost: $550
March 12-14 – MountainWest RubyConf 2009 in Salt Lake City, Utah
Cost: $100
March 26-28 – Scotland on Rails in Scotland, United Kingdom
Cost: £150
April 3-4 – Locos X Rails in Buenos Aires, Argentina
Cost: ?
April 4 – LA Ruby Conf 2009 in Los Angeles, California
Cost: $75
April 17-18 – Golden Gate Ruby Conference in San Francisco, California
Cost: ?
May 4-7 – RailsConf 2009 in Las Vegas, Nevada
Cost: $695
May 9-10 – Euruko 2009 in Barcelona, Spain
Cost: 30 Euro
May 15-18 – RailsCamp 5 in Brisbane, Australia
Cost: $120 AUD
Update
Since I initially wrote up this post, there have been several more events I’ve been made aware of (from the comments):
- RubyCamp Lyon, France, February 21, Cost: Free
- Ruby on OS X, Amsterdam, May 15-16, Cost: ?.
- Ruby DCamp Washington DC, September 18-19, Cost: Free
It’s pretty cool to see more RubyCamps. I’m a big fan of BarCamp type events where you keep admission free. Perhaps in this financial climate these types of events will prosper more then they normally do. Feel free to bug me if you want help putting one of these together or need help with publicity.
add to del.icio.us. look up in del.icio.us.
add to furlWed 28 January, 2009

add to del.icio.us. look up in del.icio.us.
add to furl
I just committed a little feature during our Rails core hackfest in Chicago: Autoloading ActiveResource schemas. Note: this is in my personal fork that’s up to date with the rails repo, and will probably be merged in for Rails 2.3.
I’ve received some requests for this from people having problems using Lighthouse::Ticket records with form_for helpers in their Rails apps. The idea is that resources can automatically load the starting XML just once, like the way ActiveRecord loads the schema from the database. This is already part of the current Rails scaffolding:
class PostsController < ApplicationController
def new
@post = Post.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @post }
end
end
end
There is one problem though, this probably won’t work for protected or nested actions. Ideally a Rails app will set a top level route for the resource, and disable any before filters if request.format.xml? is true.
map.route 'tickets/new.:format', :controller => 'tickets', :action => 'new'
You can get around this by modifying the #schema hash directly, or calling #reset_schema with your own prefixes. Here’s a sample using the Lighthouse API lib.
Lighthouse.account = 'entp'
Lighthouse.token = 'monkey'
Lighthouse::Ticket.reset_schema :project_id => 1
# or, use a well known public project
Lighthouse.account = 'rails'
Lighthouse::Ticket.reset_schema :project_id => 8994
Ticket.new # => #<Lighthouse::Ticket:0x1707898 @attributes={"permalink"=>nil, "updated_at"=>nil, "number"=>nil, "title"=>nil, "creator_id"=>nil, "tag"=>nil, "attachments_count"=>0, "priority"=>0, "closed"=>false, "assigned_user_id"=>nil, "user_id"=>nil, "created_at"=>nil, "state"=>nil, "milestone_id"=>nil}, @prefix_options={:project_id=>8994}>
Comments?
add to del.icio.us. look up in del.icio.us.
add to furl
Ilya Grigorik wrote up a post on generating a code swarm visualization from git repositories. He wrote gitter to feed the git commit info for the Rails repository and feed it to code swarm:
<object height="300" width="400"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=2979844&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /><embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=2979844&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" allowscriptaccess="always" height="300" width="400"></embed></object>
Ruby on Rails from Ilya Grigorik on Vimeo.
It’s worth checking out the HD version. Git was introduced around 4:40 :)
add to del.icio.us. look up in del.icio.us.
add to furlTue 27 January, 2009

add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furl
“ It was a time when only machines had disturbing things to say. ”
Wallace Stevens
add to del.icio.us. look up in del.icio.us.
add to furlMon 26 January, 2009

While busy getting JotBot, our time-tracking tool , out the door, we (meaning Rising Tide Software and Happy Camper Studios) were not so attentive to certain pragmatic details. We lost work with one of our larger clients; they were bought, and the new owners put an end to new development.
So Logan and I are looking for Web development and desktop application development contract work.
If you have something, or know someone, please drop me a line or give me a call.
Contact info is here
add to del.icio.us. look up in del.icio.us.
add to furl
The most popular request on our new Feedback site was for the ability to easily manage multiple models in a single form. Thankfully Eloy Duran has a patch that does just this. But before we roll it into rails 2.3 we want to get some more feedback from you guys. Eloy's written this brief introduction to the patch, so take a look, and add any feedback you have to the lighthouse ticket.
In Rails it has always been a little tricky to create a single form for both a model and its associations. Last summer, the :accessible option was committed as a first stab at a unified solution for dealing with nested models. However, this feature was pulled before the 2.2 release because it only supported nested models during object creation.
The resulting discussion on the core mailing list and our need for mass assignment have resulted in this patch for ticket #1202 which is now up for scrutinizing.
Since this is a rather large patch we would like to invite you to give it a try. Please report any issues or give feedback about the patch in general. We are especially interested to know how the provided solutions work for applications that allow deletion of nested records through their forms.
Below I'll give a quick tour on what the patch does and how to use it so you have no excuse not to give it a try.
Get the patch
Start by creating a new application:
$ mkdir -p nested-models/vendor
$ cd nested-models/vendor
Vendor your Rails branch with the nested models patches:
$ git clone git://github.com/alloy/rails.git
$ cd rails
$ git checkout origin/normalized_nested_attributes
$ cd ../..
$ ruby vendor/rails/railties/bin/rails .
An example of nested assignment
Suppose you have a project model with associated tasks:
class Project < ActiveRecord::Base
has_many :tasks
validates_presence_of :name
end
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :name
end
Now consider the following form which allows you to simultaneously create (or edit) a project and its tasks:
<form>
<div>
<label for="project_name">Project:</label>
<input type="text" name="project_name" />
</div>
<p>
<label for="task_name_1">Task:</label>
<input type="text" name="task_name_1" />
<label for="task_delete_1">Remove:</label>
<input type="checkbox" name="task_delete_1" />
</p>
<p>
<label for="task_name_2">Task:</label>
<input type="text" name="task_name_2" />
<label for="task_delete_2">Remove:</label>
<input type="checkbox" name="task_delete_2" />
</p>
</form>
Before the patch
Before this patch you would have to write a template like this:
<% form_for @project do |project_form| %>
<div>
<%= project_form.label :name, 'Project name:' %>
<%= project_form.text_field :name %>
</div>
<% @project.tasks.each do |task| %>
<% new_or_existing = task.new_record? ? 'new' : 'existing' %>
<% prefix = "project[#{new_or_existing}_task_attributes][]" %>
<% fields_for prefix, task do |task_form| %>
<p>
<div>
<%= task_form.label :name, 'Task:' %>
<%= task_form.text_field :name %>
</div>
<% unless task.new_record? %>
<div>
<%= task_form.label :_delete, 'Remove:' %>
<%= task_form.check_box :_delete %>
</div>
<% end %>
</p>
<% end %>
<% end %>
<%= project_form.submit %>
<% end %>
The controller is pretty much your average restful controller. The Project model however needs to know how to handle the nested attributes:
class Project < ActiveRecord::Base
after_update :save_tasks
def new_task_attributes=(task_attributes)
task_attributes.each do |attributes|
tasks.build(attributes)
end
end
def existing_task_attributes=(task_attributes)
tasks.reject(&:new_record?).each do |task|
attributes = task_attributes[task.id.to_s]
if attributes['_delete'] == '1'
tasks.delete(task)
else
task.attributes = attributes
end
end
end
private
def save_tasks
tasks.each do |task|
task.save(false)
end
end
validates_associated :tasks
end
The code above is based on Ryan Bates' complex-form-examples application and from the Advanced Rails Recipes book.
After this patch
First you tell the Project model to accept nested attributes for its tasks:
class Project < ActiveRecord::Base
has_many :tasks
accept_nested_attributes_for :tasks, :allow_destroy => true
end
Then you could write the following template:
<% form_for @project do |project_form| %>
<div>
<%= project_form.label :name, 'Project name:' %>
<%= project_form.text_field :name %>
</div>
<!-- Here we call fields_for on the project_form builder instance.
The block is called for each member of the tasks collection. -->
<% project_form.fields_for :tasks do |task_form| %>
<p>
<div>
<%= task_form.label :name, 'Task:' %>
<%= task_form.text_field :name %>
</div>
<% unless task_form.object.new_record? %>
<div>
<%= task_form.label :_delete, 'Remove:' %>
<%= task_form.check_box :_delete %>
</div>
<% end %>
</p>
<% end %>
<% end %>
<%= project_form.submit %>
<% end %>
As you can see this is much more concise and easier to read.
Granted, the template for this example is only slightly shorter, but it's easy to imagine the difference with more nested models. Or if the Task model had nested models of its own.
Validations
Validations simply work as you'd expect; #valid? will also validate nested models, #save(false) will save without validations, etc.
The only thing to note is that all error messages from the nested models are copied to the parent errors object for error_messages_for. This will probably change in the future, as discussed on the ticket, but that's outside of the scope of this patch.
Let's look at an example where Task validates the presence of its :name attribute:
>> project = Project.first
=> #<Project id: 1, name: "Nested models patches", created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15", author_id: 1>
>> project.tasks
=> [#<Task id: 1, project_id: 1, name: "Write 'em", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 2, project_id: 1, name: "Test 'em", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 3, project_id: 1, name: "Create demo app", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 4, project_id: 1, name: "Scrutinize", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">]
>> project.tasks.second.name = ""
=> ""
>> project.valid?
=> false
>> project.errors
=> #<ActiveRecord::Errors:0x23e4b10 @errors={"tasks_name"=>["can't be blank"]}, @base=#<Project id: 1, name: "Nested models patches", …, author_id: 1>>
Transactions
By now you are probably wondering about the consistency of your data when validations passes but saving does not. Consider this Author model which I have rigged to raise an exception after save:
class Author < ActiveRecord::Base
has_many :projects
after_save :raise_exception
def raise_exception
raise 'Oh noes!'
end
end
Here's the Project data before an update:
>> project = Project.first
=> #<Project id: 1, name: "Nested models patches", created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15", author_id: 1>
>> project.tasks
=> [#<Task id: 1, project_id: 1, name: "Write 'em", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 2, project_id: 1, name: "Test 'em", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 3, project_id: 1, name: "Create demo app", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">,
#<Task id: 4, project_id: 1, name: "Scrutinize", due_at: nil, created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">]
>> project.author
=> #<Author id: 1, name: "Eloy", created_at: "2009-01-22 11:17:15", updated_at: "2009-01-22 11:17:15">
Now let's delete the first Task and change the name of the second Task:
>> project.tasks_attributes = { "1" => { "_delete" => "1" }, "2" => { "name" => "Who needs tests anyway?!" } }
=> {"1"=>{}, "2"=>{"name"=>"Who needs tests anyway?!"}}
>> project.tasks.first.marked_for_destruction?
=> true
>> project.tasks.forty_two
=> nil # Oops, I meant #second of course… ;)
>> project.tasks.second.name
=> "Who needs tests anyway?!"
Finally, let's try to save the Project instance:
>> project.save
RuntimeError: Oh noes!
from /Users/eloy/code/complex-form-examples/app/models/author.rb:9:in `raise_exception_if_needed'
An exception was raised while saving one of the nested models. Now let's see what happened to the data:
SQL (0.1ms) BEGIN
Task Destroy (0.3ms) DELETE FROM `tasks` WHERE `id` = 1
Task Update (0.2ms) UPDATE `tasks` SET `updated_at` = '2009-01-22 11:22:23', `name` = 'Who needs tests anyway?!' WHERE `id` = 2
SQL (17.0ms) ROLLBACK
As you can see, all changes were rolled back. Both updates as well as the removal of records marked for destruction all happen inside the same transaction.
As with any transaction, the attributes of the instance that you were trying to save will not be reset. This means that after this failed transaction the first task is still marked for destruction and the second one still has the new name value.
Conclusion
This patch allows you to create forms for nested model as deep as you would want them to be. Creating, saving, and deleting should all work transparently and inside a single transaction.
Please test this patch on your application, or take a look at my fork of Ryan's complex-form-examples which uses this patch.
Your feedback is much appreciated. However, keep in mind that we can't possibly satisfy everyone's needs all at once. Please suggest additional features or major changes as a separate ticket for after the patch has been applied. The goal is to fix the bugs in this patch first so we all have a clean foundation to build on.
On a final note, I would like to thank David Dollar for the original :accessible implementation, Fingertips (where I work) for sponsoring the time that has gone into this patch, Manfred Stienstra for extensive help on the documentation, and in no particular order Lance Ivy, Michael Koziarski, Ryan Bates, Pratik Naik and Josh Susser for general discussion.
add to del.icio.us. look up in del.icio.us.
add to furl

- 什么是Rails Templates
- Rails Templates记录软件开发过程的所有命令。
- 利用什么方法记录Rails Templates?
- Ruby语言文件
- Rails Templates文件存放在哪里
- 从理论上说,任何地方;在实际中,应该存放在服务器上。
- 利用Rails Templates方法,如何开发Rails项目
- 三个步骤:(1)>= Rails 2.3,在今天Rails 2.3正式版本尚未发布之前,可以使用上面命令一方法获取它,或者参见:如何获取Rails当前开发版本(Rails Edge Version)? ;(2) 创建Rails Template文件,该文件的实例代码,如上面代码所示;(3)利用命令“rails -m [Rails Template位置及其文件名称]”,如上面二所示。
- 参考资料
- http://ryandaigle.com/articles/2008/12/11/what-s-new-in-edge-rails-application-generators
- http://ramblingsonrails.com/how-to-use-the-new-templates-in-rails
- http://github.com/imajes/rails-template/tree/master
- Rails Templates实例代码
- http://gist.github.com/33337
- Rails Templates实例代码
- http://m.onkey.org/2008/12/4/rails-templates
- 说明Rails Templates最重要的文章
- http://www.rubyinside.com/rubys-top-hitter-in-2008-jeremy-mcanally-1404.html
- http://www.railsinside.com/tips/212-rails-templates-pumped-full-of-caffeine.html
- http://github.com/rails/rails/commit/e8cc4b116c460c524961a07da92da3f323854c15
- http://ariejan.net/2009/01/04/how-to-start-a-rails-edge-app-the-easy-way/
add to del.icio.us. look up in del.icio.us.
add to furlSat 24 January, 2009


- 说明
- 下面所示的方法不影响系统安装的Rails版本。
- 这种方法的安装方法好处,该Rails版本仅仅针对该Rails项目有效。
- 参考资料
add to del.icio.us. look up in del.icio.us.
add to furl
“ It’s a fight against the idea that everything has to die when it doesn’t create turnover. ”
Florian Kaps on saving Polaroid
add to del.icio.us. look up in del.icio.us.
add to furl
January 17, 2009 -January 23, 2009
Edge Rails saw 28 commits this week. Here’s a look at some of them. As always, you’ll want to go back to the GitHub commit list if you want to look at every single change. As we near 2.3, many of the commits we’re seeing are bug fixes rather than new features, and I’m generally not covering those here.
More Rack Middleware
The Rack-ification of Rails continues, with more and more Rails code being refactored into Rack middleware. This week, parsers for XML, JSON, and YAML got moved into ActionController::ParamsParser middleware. In the long run, this sort of refactoring will make many of Rails services open to other Rack clients, without every framework needing to reinvent all of the same wheels. commit
Deprecations
If you were one of the people who got used to running script/performance/request to look at performance based on integration tests, you need to learn a new trick: that script has been removed from core Rails now. But don’t worry if you depend on it. There’s a new request_profiler plugin that you can install to get the exact same functionality back.
Also on the deprecation list is ActionController::Base#session_enabled?, which now returns a deprecation warning when you try to use it. But given that sessions are lazy-loaded now, to disable them all you need to do to disable them is to not use them in the first place. commit
Local Caching for All!
Last week, we saw an improvement to caching performance when using MemCacheStore, keeping a local request cache to avoid redundant reads. This week, that work was refactored so that it can be used with any remote store. commit
add to del.icio.us. look up in del.icio.us.
add to furl
RailsConf 2009 is now open for registration. We’re going to Las Vegas this year. More precisely the Las Vegas Hilton from May 4th through 7th. It’s going to be a party for sure.
There has been such an incredible amount of activity since last year. We have the merging of Merb back into Rails, Rails 2.2 and 2.3, and probably a good showing of Rails 3.0. So we should be absolutely packed for great content this year.
It’s going to be hard to top 2008, though. I really thought that was a fantastic show. Great lineup of proposals, great speakers, and a great sense of community. Which is pretty hard to do when you have almost 2,000 people gathered. So we’ll try extra hard this year to outdo it.
So I hope to see many familiar and new faces this year. We have early registration open until March 16th, so you can save up to $200 by getting it done early.
Don’t forget to get your speaker proposal in either. You have until February 17th.
See you all in Vegas!
add to del.icio.us. look up in del.icio.us.
add to furl
add to del.icio.us. look up in del.icio.us.
add to furlThu 22 January, 2009

有一个人在应聘过程中问了一个问题,怎么才能成为咨询师。我们给出的回答是,加入我们就是咨询师了。
写代码的人就是程序员,加入一个咨询公司,成为一个咨询师当然是顺理成章的事。不过,如同写代码和写好代码是两回事,不是成了咨询师,就能做好咨询的。在写程序上,我应该算是有些经验的,在做咨询上,我只能算是一只菜鸟。
正如我之前在blog中提到的,我们是在卷起袖子做咨询的。也正是因为要实际的做一些事,程序员的本性总会时不时的显露出来,把自己当做问题真正的解决者,而忽略了自己顾问的身份,回归到程序员的角色上。倒不是说程序员的角色不好,而是客户花钱雇我们,并不是要把我们当做程序员用,毕竟,他们已经有很多的程序员了。作为顾问,我们要提供更大的价值,也许是对人的影响,也许是一些变革。
好在我身边有一群敏锐而宽容的人,他们恰如其分的为我指出了这样的问题,让我有机会重新审视自己的定位。重新的审视也让我改变了一些自己的做法。
最近在想一个系统测试方案,之前很多时侯,这个问题只是在我脑子里面徘徊。当我开始回归顾问的角色,我找了很多不同的人一起讨论,大家的共同智慧让这个原本让我觉得有些困难的问题看到了一些曙光。有人主动承担起一些工作,于是,这个让我有心无力去解决的逐步有了一些进展。
今天和一个团队做了一次迭代回顾。记得第一次给一个团队做回顾的时侯,每每有人提出一些问题,我就会尝试去解释,于是,在过程中我说了好多,总是试图解释很多东西,结果是我觉得好累,不过,大家对我的解释理解得也有限。这次的迭代会议,好几次,我也想解释,不过,最终说出来的是,你们怎么看这个问题,结果,大家就会纷纷贡献自己的想法,甚至会引发一些讨论。探讨出来的结果显然比得到顾问的“权威”解释让人理解更加深刻。
作为一个菜鸟咨询师,我逐渐开始理解我们的目标是人。
add to del.icio.us. look up in del.icio.us.
add to furl











