Get a quote!

Blog

New Version of Rails, Arriving on Track 2

Written by Jared Haworth on

OK, title aside, no train puns from me today… this is exciting news!

Rails 2.0 has reached Preview Release status. Despite the Microsoft-esque syntax, the mood is overwhelmingly upbeat. Personally, I’ve been using Edge Rails for all my new development over the past 6 months, but this final drive by the Rails Core team and core contributors has included some great new goodies.

The changes to the Routing system have received plenty of attention elsewhere, but I wanted to pull out one tidbit which I’ve only seen posted one other place, Casper Fabricius’ excellent recap of DHH’s keynote address at Railsconf Europe:

Namespaced Routes are awesome, and a long-overdue addition for any of us who’ve attempted to create an administration section for our sites. There’s a clever bit of form_for syntax for dealing with namespaced routes.

The Old Way
form_for :user, :url => admin_users_path do |f|
  # new user form 
end

form_for :user, :url => admin_user_path(@user), 
                :html => { :method => :put } do |f|
  # edit user form
end
The New Way
form_for([:admin, @user]) do |f|
  # Works for either!
end

Cleaner, more concise, and thoroughly overlooked. Casper, thanks for bringing this out so we could see it!

When Things Get Saved...

Written by Jared Haworth on

Having been excited about the upcoming Rails 2.0 release since I saw DHH speak in Portland at Railsconf, I’ve been starting all my new projects on Edge Rails in anticipation of the new version.

While bringing one of my projects up-to-date with the Preview Release, I came across something relatively new that (to my mind) breaks the long-standing logic of “When Things Get Saved.”

I’ve been trying to keep with the Skinny Controller, Fat Model approach outlined by Jamis Buck, so I’ve moved the logic for creating my associated models out of the controller, and into the model.

My specific example deals with a semi-complex form, registering new users. I needed to create a Company, a User, an Employee and some defaults, by simply prompting the user for a minimal amount of data (Company Name, First and Last name, email, password). My Company model has the following associations:

belongs_to :owner, :class_name => "User", :foreign_key => "owner_id"
has_many :employees, :class_name => "Employee", :foreign_key => "employer_id"
has_one :company_setting

The following snippet is taken from the Company model, this method instantiates a new company object, sets the owner, creates the first employee, assigns roles to the employee, and sets the default variables for the company’s details.

def self.create_with_associations(options)
  returning new do |company|
  company.attributes = options[:company]
  company.create_owner(options[:user])
  employee = company.employees.create(:title => "Owner", :phone => company.phone, :user => company.owner)
  Role.find(:all).each { |role| employee.roles << role }
  company.create_company_setting(:hours_per_day => 8, :hours_per_week => 40)
end   end

Unfortunately, Changeset 7511 has rendered that snippet useless. The new rule states that the .create method cannot be called on an association for an unsaved parent. Previously, the code above would instantiate a new Company object, then silently save it when the owner was assigned. Now, that line throws an exception instead.

Here’s the Rails 2.0-compatible version. I’m not sure I like it as much.

def create_with_associations(options)      
  company = self.create(options[:company])
  owner = company.build_owner(options[:user])
  employee = company.employees.build(:title => "Owner", :phone => company.phone, :user => company.owner)
  Role.find(:all).each { |role| employee.roles << role }
  setting = company.build_company_setting(:hours_per_day => 8, :hours_per_week => 40)
  company
end

I think I need to approach the whole tangle from another angle. Perhaps I need to use the User as the base unit, instead of the Company, and build my associations from there?