TwitterFacebookGoogle

Cloning an object for creation in Ruby

Ruby provides two methods for creating a copy of an object: clone() and dup(). Starting from Rails 3.1, the behavior of these methods has somewhat changed. In this post, I’ll point out some of the differences as they relate to record creation and also share some helpful pointers when constructing and saving a new object-graph.

Let’s say we’ve got the following classes:

class Unit
  attr_accessible :name, :division_id
  belongs_to :division
 
  validates :name, presence :true
  validates :division, presence :true
 
  validates_uniqueness_of :name, :scope => [:division_id], :case_sensitive => false, :on => :create	 
end
 
class Division
  attr_accessible :name, :user_id
  belongs_to :user
 
  validates :name, presence :true
  validates :user, presence :true
end
 
class User
  #... your good 'ole user class
end

The Scenario

What we’d like to do is create a copy of an existing unit, add it to a brand-new division that belongs to some user and then call user.save(). What we’d expect to see is that:

- A new division is created and associated with the user
- A new unit is created and associated with the newly created division

Understanding clone vs. dup

Let’s first look at the major differences between clone() and dup() so we know which method to use for our specific scenario.

One difference is that clone() does not mark the copy as a new_record while dup() does:

  >> u_clone = Unit.first.clone
  >> u_clone.new_record?
  >> = false
  >>
  >> u_dup = Unit.first.dup
  >> u_dup.new_record?
  >> = true

As a consequence, dup() blanks out the id, created_at and updated_at attributes whereas clone() does not.

Another difference is that clone() copies over the contents plus the internal state and singleton methods whereas dup() only copies over the contents.

Creating and persisting our object graph

In our case, because we wish to create a new unit and add it to a new division, it looks like dup() is what we need. Let’s give it a shot and see what happens:

 >> usr = User.first
 >> d1 = usr.divisions.build({ name: "Divison 1" })
 >> d1.units << Unit.first.dup
 >> usr.save
 >>

What we are doing in the code snippet above is picking the first user, adding a new Division to the user’s divisions collection, adding a new Unit to the divison and then calling save on the user. Think it’ll work? Let’s look at the next line to see what transpired:

  >> usr.save
  >> = false

Oops, didn’t work! Let’s look at the error messages to see what went wrong:

  >> usr.save
  >> = false
  >> usr.errors
  >> [divisions: 'is invalid']
  >> usr.divisions.last.errors
  >> [units: 'is invalid']
  >> usr.divisions.last.units.first.errors
  >> [division: "can't be blank"]

Hmm…division can’t be blank! If you scroll to the class definition of Unit, you’ll notice that we have a validation rule that enforces that division can’t be blank. If we got rid of that validation rule then the above usr.save() would passed. This is because Rails is smart enough to recognize that a new unit is being added to a new division and so it’ll first create the division inside the database, assign the division to unit and the create the unit inside the database.

So, why doesn’t that work with the validation rule being present? Because Rails runs validation on the entire object graph before persisting anything to the database! Since, in our case, we are adding a new unit to a new division, unit.division is nil and hence our validation that states “Unit must have division” fails and nothing is persisted. To make this work without removing the validation rule, what we’ll need to do is add the following additional lines:

 >> u_dup = Unit.first.dup
 >> u_dup.division = d1

Or a better approach is to override the dup() method so that it accepts division as a parameter:

class Unit
   ...
 
  def dup(division) 
    u_dup = super()
    u_dup.division = divison
    u_dup
  end	 
 
  ...
end

And now the following will work successfully:

 >> usr = User.first
 >> d1 = usr.divisions.build({ name: "Divison 1" })
 >> d1.units << Unit.first.dup
 >> usr.save
 >> = true

Hopefully, this gave you some insight into how clone() and dup() work and it’ll save you some headache the next time you need to persist an object graph!

Twitter Email Linkedin Digg Stumbleupon Subscribe

Bulk INSERT from within a Rake task

Recently, I had to insert a ton of sample data into our test database to facilitate testing. My first attempt was to use the activerecord-import gem. Looks pretty promising but for some odd reason I just couldn’t get it work from inside a Rake task. It kept inserting data in sequential order instead of doing BULK inserts.

Well, after some R&D, I came across a “simpler” solution that doesn’t require the use of any additional gems. It turns out that all I had to do was wrap all of my inserts inside one transaction. This speeds up the inserts by a HUGE factor when compared with sequential inserts – ~200 ms vs. 1000 ms for about 10 records! An additional benefit of this approach is that all of your model validations still run as they normally would.

Below is a code snippet:

def make_users
  puts "Creating users..."
  users = []
  10.times do |n|
    users << User.new(
      full_name: "User #{n}", 
      email: "user_#{n}@test.com", 
      password: "foobar",
      password_confirmation: "foobar")
  end
  User.transaction do 
    users.each { |u| u.save }
  end
  puts "Finished creating users."
end

Bye bye, activerecord-import gem! I am sticking with the transaction wrapper!

Twitter Email Linkedin Digg Stumbleupon Subscribe

Show/hide various sections of a page using JQuery and CSS

In this post I’ll go over how you can utilize JQuery and CSS classes to show/hide various parts across the different sections of a page without creating a mess!

The Challenge
You’ve got a wizard-like page with multiple steps and you want to be able to show/hide various elements based upon the current step. Below is a dumbed-down example:

The colored boxes represent the parts that are being shared across the various sections of the page. For instance, the green box is being shared by the ‘Image Selection’ and ‘Order Confirmation’ sections. While the red box is being shared by all three sections.

So the challenge is: How do we show/hide these various parts across the sections of the page without making a mess? And by mess, I refer to duplicate code and/or little <% if..then %> snippets scattered throughout the page.

The Solution
By using some CSS/JQuery trickery, of course! What we’ll do is introduce some CSS classes that we will then apply to the various parts for which we need to handle visibility. Here are the classes that we will need:

  • section – Represents a section
  • requestor – Represents the requestor section
  • image-selection – Represents the image selection section
  • confirmation – Represents the order confirmation section

The CSS classes will then be applied to the various parts based upon the section inside which the part is to be shown:

<div>
  <input type='hidden' id='section-to-show' />
  <table>
    <tr>
      <td>Request Type:</td>
      <td class='section requestor'>
        <select>...</select>
      </td>
      <td class='section image-selection confirmation'>
        <%= selectedRequestType %>
      </td>
    </tr>
    ...
    <tr>
      <td>First Name:</td>
      <td><%= firstName %></td>
    </tr> 
    <tr>
      <td>Last Name:</td>
      <td><%= lastName %></td>
    </tr> 
    <tr class='section requestor confirmation'>
      <td>Email</td>
      <td><%= email %></td> 
    </tr>
    ...
    ...
    <tr class='section image-selection confirmation'>
      <td>Image</td>
      <td class='section image-selection'>
        Browse...
      </td>
      <td class='section confirmation'>
        <img src='..' />
      </td>
    </tr>
    ...
  </table>
</div>

A few things to highlight:

– The hidden input field ‘section-to-show’ indicates the section to display. It’s value is set by the server-side code.
– There are two table columns inside the first table row. Only one will be visible based up the section that is being displayed.
– The first name and last name table rows don’t have any classes applied to them. This is because they are always visible.
– The last table row shown above gives an example of how you can make the visibility conditional for both the table row and the table column.
– I skipped various rows in the HTML form above to save some typing and to avoid being repetitive.

And now for the JQuery:

  $(document).ready(function(){
 
    // hide all sections to begin with
    $('.section').hide();
 
    current_section = $('#section-to-show').val();
    $("." + current_section).show();
  });

And there you have it – a cleaner alternative to showing and hiding various parts across the sections of a page!

Twitter Email Linkedin Digg Stumbleupon Subscribe
CyberChimps