Be Genius

Fork Me
Mugshot

Hi, I'm Bodaniel Jeanes.

I'm a Ruby developer from Brisbane, Australia

I work at Mocra where I hack on awesome code. Follow me, recommend me, and link with me.

Using accepts_nested_attributes_for When the Child Object validates_presence_of Parent

I came across an interesting dilemma today in Rails 2.3 whilst trying to use accepts_nested_attributes_for.

The models I have were:

1
2
3
4
5
6
7
8
9
class Organization < ActiveRecord::Base has_many :users accepts_nested_attributes_for :users end class User < ActiveRecord::Base belongs_to :organization validates_presence_of :organization end

I had an “Organization” creation form which allowed an administrator to create an Organization and an initial user for it. However, even though I had filled in all the required fields to pass the validations I was constantly getting the following error: Organization can not be blank.

Digging deeper I found that when an object is added to an association via the association.build method, the parent object isn’t actually set:

1
2
3
4
5
6
>> o = Organization.new(:name => "Test") => #<Organization id: nil, name: "Test"> >> u = o.users.build(:name => "Test User") => #<User id: nil, organization_id: nil, name: "Test User"> >> u.organization => nil

Apparently this flaw also applies to accepts_nested_attributes_for. When I send through the User params through from my form normally with the Organization params, it creates the User object in the users association as you’d expect, but raises a validation error because the User instance doesn’t recognise that it is has a parent Organization

My quick 5 minute fix was to modify the Organization model thusly:

1
2
3
4
5
6
7
8
9
10
class Organization < ActiveRecord::Base has_many :users accepts_nested_attributes_for :users def users_attributes_with_self_assignment=(attributes) self.users_attributes_without_self_assignment = attributes users.each { |u| u.organization = self } end alias_method_chain :users_attributes=, :self_assignment end

Related Rails bugs seem to be here and here. This patch will also solve the problem and is currently in edge, but didn’t make it in time for Rails 2.3.

Unescaping UTF-8 Strings in Ruby 1.9

Today Radar and I encountered a little issue with String encodings in Ruby 1.9. In this project, some Merb UTF-8 params needed to be unescaped. We spent some trying to force strings into UTF-8 encoding but for some reason while the encoding was UTF-8, the actual contents of the strings were getting massacred.

Long story short:

1
2
3
4
5
6
7
# In Ruby 1.9 # Broken puts URI::unescape("Baden-W%C3%BCrttemberg") # => "Baden-Württemberg" # Working puts CGI::unescape("Baden-W%C3%BCrttemberg") # => "Baden-Württemberg"

Another lesson we learnt on our adventures today is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# In Ruby 1.9 m1 = "Munich" puts = m1.encoding # let's suppose it is something other than UTF-8, such as ASCII-8Bit m2 = "München" puts = m2.encoding # let's suppose we have a UTF-8 encoded string # The following will raise an exception about mismatched encodings m3 = m1 << m2 # The easiest way to get around this is to do the concatenation like so: m3 = m3 = m1 << m2.force_encoding("UTF-8")