Has_and_belongs_to_many and dynamic find

Hi

Just curious if anyone can explain why using a dynamic find fails to
work with << operator

I have standard habtm relationship

class User < ActiveRecord::Base

has_and_belongs_to_many :roles

Now when I assign a Role via << after saving the new User I get wierd
behaviour
but only when using the dynamic version of find

i.e

@user = User.new§

  if @user.save

    # FOLLOWING DOES NOT WORK
    # @user.roles << Role.find_by_name( 'registered' )

    # But this this is Fine !
    @user.roles << Role.find( :first, :conditions => ['name = ?',

‘registered’] )

When using the usal find( :first) style everythign is sweet,
associaiton is built and appears in DB.

However when using the find_by_name association_proxy.rb throws an
exception but the error I get is somewhat cryptic as it appears as if
the result of find_by_name is a ‘Role’ as expected :

“Role expected, got Role”

Chances are I’m doing something obviously wrong, and not really a
problemn as I can use find :first … but still curious, why does
find_by_name blow up ?

Cheers all,
tom

The full trace is here

C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/
associations/association_proxy.rb:148:in raise_on_type_mismatch' C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/ associations/association_collection.rb:24:in<<’
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/
associations/association_collection.rb:23:in each' C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/ associations/association_collection.rb:23:in<<’
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/
connection_adapters/abstract/database_statements.rb:59:in
transaction' C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/ transactions.rb:95:intransaction’
C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/
transactions.rb:121:in transaction' C:/ruby/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/ associations/association_collection.rb:22:in<<’
#{RAILS_ROOT}/app/controllers/user_controller.rb:176:in `new’

    # FOLLOWING DOES NOT WORK
    # @user.roles << Role.find_by_name( 'registered' )

if Role.find_by_name(‘registered’) returns more than one record (which,
by definition :first will avoid) you may have this problem…

what-say-u? if the :name isn’t unique, and u got a couple names with
‘registered’ for the value … you should be getting TypeMismatch, as
you’re trying to associate an array instead of a Role to a @user.

makes any sense?

Hi shai, thanks for the response.

Yep does make sense but in this case there is definitly only one such
Role in the DB,
and also strikes me as odd that the error message says 'Role expected,
got Role"

Of course the message may simply be constructed wrongly, but I would
expect
'Role expected, got Array"

If I get time I will try and unravel the dynamic version, as I would
expect under the hood, the two calls should be equivalent.

cheers
tom

Well looks like this is common problem, probably a rails bug … not
sure if it’s been raised as such but anyway, I found a post with a
good workaround

see…

http://www.ruby-forum.com/topic/101817

where you define the assocation directly require the other model
file … e.g. in user.rb add

require File.dirname(FILE)+‘/role.rb’