Daily Refactor #70: Inline Temp in SourceVersion#migrate

The Refactoring

Today’s refactoring is just like yesterday’s but I wanted to show a quick tip with #create! I didn’t mention.

Before

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SourceVersion < ActiveRecord::Base
  include SecondDatabase
  set_table_name :versions
 
  def self.migrate
    all.each do |source_version|
      v = Version.new
      v.attributes = source_version.attributes
      v.project = Project.find(RedmineMerge::Mapper.get_new_project_id(source_version.project_id))
      v.save!
 
      RedmineMerge::Mapper.add_version(source_version.id, v.id)
    end
  end
end

After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SourceVersion < ActiveRecord::Base
  include SecondDatabase
  set_table_name :versions
 
  def self.migrate
    all.each do |source_version|
      version = Version.create!(source_version.attributes) do |v|
        v.project = Project.find(RedmineMerge::Mapper.get_new_project_id(source_version.project_id))
      end
 
      RedmineMerge::Mapper.add_version(source_version.id, version.id)
    end
  end
end

Review

The difference between this refactoring and yesterday’s is that I need to keep track of the saved objects for RedmineMerge::Mapper. Since I removed the v temporary variable and used #create! I need to reintroduce a variable that represents the saved Version. Luckily, #create! returns the saved object when it’s successful so the flow ends up:

  1. Version.create! builds a new Version object, v.
  2. v gets it’s attributes set.
  3. v is yielded to the block, picking up it’s project attribute through the setter (v.project=).
  4. The block returns and Version.create! tries to save. If saving fails, an Exception is thrown and Ruby jumps up the stack until the script exits.
  5. If saving was successful, Version.create! returns the saved Version object setting it to the local variable version.
  6. RedmineMerge::Mapper can now use the local variable version.

Not bad for 4 lines of Ruby.

Reference commit