Luis Correa d''Almeida
2010-Jul-28  23:44 UTC
ActiveRecord associations seem to assume primary keys are always integers
Beyond issues in migrations (http://groups.google.com/group/
rubyonrails-core/browse_thread/thread/
cf8ae1f3e26b96f2/4ea93be5e77aed92?lnk=gst&q=primary
+key#4ea93be5e77aed92) ActiveRecord (3.0.0beta4) associations seem to
assume a primary key is always meant to be an integer.
For instance, the following will fail. Assuming records with primary
keys "uid1", "uid2", and "uid3" exist and are of
the expected type
(Medium),
@flashbck.medium_ids = ["uid1", "uid2", "uid3"]
will fail. Trace below
ActiveRecord::AssociationTypeMismatch (Medium(#13305080) expected, got
NilClass(#645570)):
/Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations/association_proxy.rb:258:in
`raise_on_type_mismatch''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations/association_collection.rb:347:in
`replace''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations/association_collection.rb:347:in `each''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations/association_collection.rb:347:in
`replace''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations.rb:1417:in `media=''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations.rb:1423:in `send''
  /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/
lib/active_record/associations.rb:1423:in `medium_ids=''
  /Users/luis/Projects/flashbck/app/controllers/
flashbcks_controller.rb:22:in `create''
NilClass is the result of Medium.find(0) as opposed to
Medium.find("uid1"). This happens because the ids are converted to
integers, below.
Looking into associations.rb (http://github.com/rails/rails/blob/
master/activerecord/lib/active_record/associations.rb around line
1430) the following looks suspicious.
        def collection_accessor_methods(reflection,
association_proxy_class, writer = true)
          collection_reader_method(reflection,
association_proxy_class)
          if writer
            define_method("#{reflection.name}=") do |new_value|
              # Loads proxy class instance (defined in
collection_reader_method) if not already loaded
              association = send(reflection.name)
              association.replace(new_value)
              association
            end
            define_method("#{reflection.name.to_s.singularize}_ids=")
do |new_value|
              ids = (new_value || []).reject { |nid|
nid.blank? }.map(&:to_i)
              send("#{reflection.name}=",
reflection.klass.find(ids).index_by(&:id).values_at(*ids))
            end
          end
        end
The following line calls to_i on all ids.
ids = (new_value || []).reject { |nid| nid.blank? }.map(&:to_i)
This does not seem to be expected behavior. I was under the impression
that non-integer based primary keys were supported by activerecord.
Any thoughts?
-- 
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Core" group.
To post to this group, send email to rubyonrails-core@googlegroups.com.
To unsubscribe from this group, send email to
rubyonrails-core+unsubscribe@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/rubyonrails-core?hl=en.
Robert Pankowecki
2010-Jul-29  06:29 UTC
Re: ActiveRecord associations seem to assume primary keys are always integers
On Thu, Jul 29, 2010 at 1:44 AM, Luis Correa d''Almeida <luis.ca@gmail.com> wrote:> Beyond issues in migrations (http://groups.google.com/group/ > rubyonrails-core/browse_thread/thread/ > cf8ae1f3e26b96f2/4ea93be5e77aed92?lnk=gst&q=primary > +key#4ea93be5e77aed92) ActiveRecord (3.0.0beta4) associations seem to > assume a primary key is always meant to be an integer. > > For instance, the following will fail. Assuming records with primary > keys "uid1", "uid2", and "uid3" exist and are of the expected type > (Medium), > > @flashbck.medium_ids = ["uid1", "uid2", "uid3"] > > will fail. Trace below > > ActiveRecord::AssociationTypeMismatch (Medium(#13305080) expected, got > NilClass(#645570)): > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations/association_proxy.rb:258:in > `raise_on_type_mismatch'' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations/association_collection.rb:347:in > `replace'' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations/association_collection.rb:347:in `each'' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations/association_collection.rb:347:in > `replace'' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations.rb:1417:in `media='' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations.rb:1423:in `send'' > /Users/luis/.rvm/gems/ruby-1.8.7-p249/gems/activerecord-3.0.0.beta4/ > lib/active_record/associations.rb:1423:in `medium_ids='' > /Users/luis/Projects/flashbck/app/controllers/ > flashbcks_controller.rb:22:in `create'' > > NilClass is the result of Medium.find(0) as opposed to > Medium.find("uid1"). This happens because the ids are converted to > integers, below. > > Looking into associations.rb (http://github.com/rails/rails/blob/ > master/activerecord/lib/active_record/associations.rb around line > 1430) the following looks suspicious. > > > def collection_accessor_methods(reflection, > association_proxy_class, writer = true) > collection_reader_method(reflection, > association_proxy_class) > > if writer > define_method("#{reflection.name}=") do |new_value| > # Loads proxy class instance (defined in > collection_reader_method) if not already loaded > association = send(reflection.name) > association.replace(new_value) > association > end > > define_method("#{reflection.name.to_s.singularize}_ids=") > do |new_value| > ids = (new_value || []).reject { |nid| > nid.blank? }.map(&:to_i) > send("#{reflection.name}=", > reflection.klass.find(ids).index_by(&:id).values_at(*ids)) > end > end > end > > The following line calls to_i on all ids. > > ids = (new_value || []).reject { |nid| nid.blank? }.map(&:to_i) > > This does not seem to be expected behavior. I was under the impression > that non-integer based primary keys were supported by activerecord. > Any thoughts?https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/5125-collection_singular_ids-method-raises-an-exception-when-primary_key-is-string-rails-3 There is patch for this issue. You might want to verify so it is applied faster. Robert Pankowecki -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.