Greetings all,

  I'm having a weird problem with a habtm relationship and honestly
I'm beginning to think I may have stumbled upon some weird bug in
rails 3.  Surely I'm crazy though.  I've been beating my head against
the wall on this for 3 days, have googled everything under the sun I
can think of and still can't come up with an answer.

Ok, the situation:

I'm creating a Rails app to replace both a Java app and a PHP app
(java application and php front-end).  This is going to be a phased
operation with the first phase being the Rails application takes over
registration and billing.  In order to do this, the Rails application
must create data in the databases for the Java and PHP apps.  The
Rails application itself is using Devise for authentication.

In database.yml I have my standard 3 databases defined and also a
connection defined for the Java apps database.
Here are pieces of the model definitions for the external object (I'm
just creating regular rails models to talk to the external databases):

class Pushbroom::UserAccount < ActiveRecord::Base
  require 'digest/md5'
  require 'base64'

  establish_connection :pushbroom
  set_table_name :user_account
  set_primary_key :id

  has_and_belongs_to_many :user_roles, :join_table =>
'pb_prod.users_roles', :class_name =>
'Pushbroom::UserRole', :foreign_key =>
'user_account_id', :association_foreign_key => 'user_role_id'
  belongs_to :user, :dependent => :destroy


 
attr_accessible :user_roles, :admin_notes, :enabled, :username, :password_hash, 
:prefStore, :accepted_tos, :do_not_contact

end


class Pushbroom::UserRole < ActiveRecord::Base

  establish_connection :pushbroom
  set_table_name :user_role
  set_primary_key :id

  has_and_belongs_to_many :user_accounts, :join_table =>
'pb_prod.users_roles', :class_name =>
'Pushbroom::UserAccount', :foreign_key =>
'user_role_id', :association_foreign_key => 'user_account_id'


end

And finally my Rails application user object:


class User < ActiveRecord::Base


  before_validation :capture_plaintext_password, :on => :create
  before_save :create_pushbroom_user_data
  after_save :send_welcome_email

  # Include default devise modules. Others available are:
 
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable
and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  belongs_to :pb_user_account, :class_name =>
"Pushbroom::UserAccount", :foreign_key =>
"pb_user_account_id", :dependent => :destroy, :autosave => true

  # Setup accessible (or protected) attributes for your model
 
attr_accessible :first_name, :last_name, :username, :dob, :email, :password, 
:password_confirmation, :remember_me

  validates_presence_of :first_name, :last_name, :username, :dob
  validates_date :dob, :on_or_after => lambda
{ 100.years.ago }, :on_or_after_message => "must be on or after
#{100.years.ago.strftime('%m-%d-%Y')}"
  validates_date :dob, :on_or_before => lambda
{ 13.years.ago }, :on_or_before_message => "must be on or before
#{13.years.ago.strftime('%m-%d-%Y')}"


  def capture_plaintext_password
    @plaintext_password = self.password
  end


  def create_pushbroom_user_data
    pb_user = create_pushbroom_user
    add_trial_subscription_to_pb_user(pb_user)
    pb_user_account = create_pushbroom_user_account(pb_user)
    add_subscription_plan_roles_to_pb_user_account(pb_user_account)
    self.pb_user_account = pb_user_account
  end

  def create_pushbroom_user
    pb_user = Pushbroom::User.new
    pb_user.attributes = self.attributes.slice(
      "email",
      "first_name",
      "last_name",
      "dob")

    pb_user
  end

  def add_trial_subscription_to_pb_user(pb_user)
    subscription = Pushbroom::Subscription.new
 
subscription.populate_from_subscription_plan(Pushbroom::SubscriptionPlan.find_by_name("TRIAL"))
    pb_user.subscriptions << subscription
  end


  def add_subscription_plan_roles_to_pb_user_account(pb_user_account)
    roles_granted =
pb_user_account.user.subscriptions.first.subscription_plan.roles_granted
    pb_user_account.user_roles = roles_granted
  end

  def create_pushbroom_user_account(pb_user)
    pb_user_account = Pushbroom::UserAccount.new
    pb_user_account.enabled = true
    pb_user_account.password_hash =
Pushbroom::UserAccount.create_password_digest(@plaintext_password,
self.username)
    pb_user_account.username = self.username
    pb_user_account.user = pb_user

    pb_user_account
  end

  def send_welcome_email
    AccountMailer.welcome(self).deliver
  end
end

Seems like it should be pretty vanilla.  The ONLY weirdness here is
that they aren't in the native rails database and one of the fields is
named funny in the relations table.

So here's a rails console session where I create a rails user, call
the method to create the external objects, then try to save:

ruby-1.9.2-p180 :001 > def user_fred
ruby-1.9.2-p180 :002?>       {
ruby-1.9.2-p180 :003 >             :first_name => "Fred",
ruby-1.9.2-p180 :004 >             :last_name => "Flinstone",
ruby-1.9.2-p180 :005 >             :username => "fflint",
ruby-1.9.2-p180 :006 >             :dob => "1986-06-01",
ruby-1.9.2-p180 :007 >             :email => "[email protected]",
ruby-1.9.2-p180 :008 >             :password => "badpass"
ruby-1.9.2-p180 :009?>         }
ruby-1.9.2-p180 :010?>     end
 => nil
ruby-1.9.2-p180 :011 > user = User.new(user_fred)
 => #<User id: nil, email: "[email protected]", encrypted_password:
"$2a$10$IiEOEoSnXIrP7VJAQYckfOVXuzm7Y5ZGo20ayLpSkHhz...",
reset_password_token: nil, remember_created_at: nil, sign_in_count: 0,
current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip:
nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil,
first_name: "Fred", last_name: "Flinstone", username: "fflint", dob:
"1986-06-01", pb_user_account_id: nil>
ruby-1.9.2-p180 :012 > user.create_pushbroom_user_data
 => #<Pushbroom::UserAccount id: nil, created_by: nil, created_at:
nil, updated_by: nil, updated_at: nil, admin_notes: nil, enabled:
true, username: "fflint", password_hash: "blah blah", user_id: nil,
prefStore: nil, accepted_tos: nil, do_not_contact: nil>
ruby-1.9.2-p180 :013 > user.pb_user_account.user_roles
 => [#<Pushbroom::UserRole id: 1, created_by: "script", created_at:
"2008-11-10 12:10:44", updated_by: "script", updated_at: "2008-11-10
12:10:44", admin_notes: "", name: "user", description: "Generic User
Role", conditional: false>]
ruby-1.9.2-p180 :014 > user.save!
NoMethodError: undefined method `relation' for nil:NilClass
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activesupport-3.0.5/lib/active_support/whiny_nil.rb:48:in
`method_missing'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/arel-2.0.9/
lib/arel/insert_manager.rb:22:in `insert'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/arel-2.0.9/
lib/arel/crud.rb:26:in `insert'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/
has_and_belongs_to_many_association.rb:76:in `insert_record'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:
151:in `send'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/autosave_association.rb:306:in
`block in save_collection_association'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/
association_collection.rb:431:in `block in method_missing'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:
216:in `block in method_missing'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:
216:in `each'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:
216:in `method_missing'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/associations/
association_collection.rb:431:in `method_missing'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/autosave_association.rb:297:in
`save_collection_association'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/autosave_association.rb:163:in
`block in add_autosave_association_callbacks'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activesupport-3.0.5/lib/active_support/callbacks.rb:415:in
`_run_create_callbacks'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/callbacks.rb:281:in `create'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/persistence.rb:246:in
`create_or_update'
... 18 levels...
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/callbacks.rb:277:in
`create_or_update'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/persistence.rb:56:in `save!'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/validations.rb:49:in `save!'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/attribute_methods/dirty.rb:30:in
`save!'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/transactions.rb:245:in `block in
save!'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/transactions.rb:292:in `block in
with_transaction_returning_status'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/connection_adapters/abstract/
database_statements.rb:139:in `transaction'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/transactions.rb:207:in
`transaction'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/transactions.rb:290:in
`with_transaction_returning_status'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
activerecord-3.0.5/lib/active_record/transactions.rb:245:in `save!'
  from (irb):14
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
railties-3.0.5/lib/rails/commands/console.rb:44:in `start'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
railties-3.0.5/lib/rails/commands/console.rb:8:in `start'
  from /Users/gander/.rvm/gems/ruby-1.9.2-p180@sms2/gems/
railties-3.0.5/lib/rails/commands.rb:23:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'ruby-1.9.2-p180 :015 >

If I remove the role assignment, everything is just peachy (finds,
saves, destroys, etc), but the second I try to save roles everything
blows sky-high with this message that, frankly, I don't get.  It knows
its got the roles, there is no nil object that I can tell. . .and
basically if I wasn't already bald I'd be pulling my hair out ; )

Any insight into this is EXTREMELY appreciated!

Gerald

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to