2011-04-12 44 views
0

大家好,Rails habtm悲傷我啞或軌道錯誤? (絕望)

我在用的habtm關係一個奇怪的問題和誠實,我開始覺得我可能對在軌3.一些奇怪的錯誤絆倒當然我瘋了,雖然。我已經在頭上貼着我的頭撞了3天,在我想到的太陽下搜索了一切,但仍然無法提供答案。

好了,這種情況:

我創建一個Rails應用程序來取代既有的Java應用程序和PHP應用程序(Java應用程序和PHP前端)。這將是一個分階段的操作,第一階段是Rails應用程序接管註冊和計費。爲了做到這一點,Rails應用程序必須在Java和PHP應用程序的數據庫中創建數據。 Rails應用程序本身正在使用Devise進行身份驗證。

在database.yml中我定義了我的標準3數據庫併爲Java應用程序數據庫定義了一個連接。

下面是對於外部物體的模型定義塊(我只是創建正軌型號交談的外部數據庫):

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 

最後我的Rails應用程序的用戶對象:

class User < ActiveRecord::Base 

    after_create :send_welcome_email 
    before_save :create_pushbroom_user_data 

    # 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 create_pushbroom_user_data 
    pb_user = create_pushbroom_user 
    pb_user_account = create_pushbroom_user_account(pb_user) 
    pb_user_account.user_roles << Pushbroom::UserRole.find_by_name('user') 
    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 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 

似乎它應該是相當香草。這裏唯一的奇怪之處在於它們不在原生軌道數據庫中,其中一個字段在關係表中名爲funny。

所以這裏就是我創建Rails用戶軌控制檯會話,調用該方法來創建外部對象,然後嘗試保存:

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/[email protected]/gems/activesupport- 3.0.5/lib/active_support/whiny_nil.rb:48:in `method_missing' 
    from /Users/gander/.rvm/gems/[email protected]/gems/arel- 2.0.9/lib/arel/insert_manager.rb:22:in `insert' 
    from /Users/gander/.rvm/gems/[email protected]/gems/arel- 2.0.9/lib/arel/crud.rb:26:in `insert' 
    from /Users/gander/.rvm/gems/[email protected]/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/[email protected]/gems/activerecord- 3.0.5/lib/active_record/associations/association_proxy.rb:151:in `send' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:306:in `block in  save_collection_association' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/associations/association_collection.rb:431:in `block in  method_missing' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `block in method_missing' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `each' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `method_missing' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/associations/association_collection.rb:431:in `method_missing' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:297:in `save_collection_association' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:163:in `block in add_autosave_association_callbacks' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activesupport-3.0.5/lib/active_support/callbacks.rb:415:in `_run_create_callbacks' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/callbacks.rb:281:in `create' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/persistence.rb:246:in `create_or_update' 
... 18 levels... 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/callbacks.rb:277:in `create_or_update' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/persistence.rb:56:in `save!' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/validations.rb:49:in `save!' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/attribute_methods/dirty.rb:30:in `save!' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/transactions.rb:245:in `block in save!' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord- 3.0.5/lib/active_record/transactions.rb:292:in `block in with_transaction_returning_status' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in  `transaction' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/transactions.rb:207:in `transaction' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/transactions.rb:290:in `with_transaction_returning_status' 
    from /Users/gander/.rvm/gems/[email protected]/gems/activerecord-3.0.5/lib/active_record/transactions.rb:245:in `save!' 
    from (irb):14 
    from /Users/gander/.rvm/gems/[email protected]/gems/railties-3.0.5/lib/rails/commands/console.rb:44:in `start' 
    from /Users/gander/.rvm/gems/[email protected]/gems/railties-3.0.5/lib/rails/commands/console.rb:8:in `start' 
    from /Users/gander/.rvm/gems/[email protected]/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 > 

如果我刪除角色分配,一切都只是桃色(發現,拯救,摧毀等),但第二次嘗試拯救角色的時候,所有的事情都會隨着這個信息而猛然升起,坦率地說,我不明白。它知道它得到了角色,我沒有可以告訴的無對象。 。 。基本上,如果我還沒有禿頭,我會把我的頭髮拉出來; )

任何洞察到這一點極爲讚賞!

傑拉德

P.S.也在這裏問http://railsforum.com/viewtopic.php?id=43647如果找到答案,會重複答案。

+0

請添加您的'create_pushbroom_user_account'方法定義 – ctcherry 2011-04-12 18:13:09

+0

糟糕,在切割和粘貼的地方迷路了。在代碼中添加備份。感謝您的支持。 – Gerald 2011-04-12 19:35:27

回答

1

在我爲此敲打了4天之後,我終於找到了問題:Rails(habtm)沒有能力確定用於外部關係表的數據庫。我也找到了答案,它甚至沒有味道不好!這裏有一個完整的線程:http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/c5655d0442039ccd

答案? has_many:通過 - 我從來沒有仔細看過,但它實際上是一個非常好的功能(即使在其他情況下)。

基本上這隻允許我創建一個代表關係的模型類。因爲我有一個模型類,我可以明確指定要連接的數據庫。

爲子孫後代着想,下面的代碼:

class Pushbroom::UsersRolesRelationship < ActiveRecord::Base 

    establish_connection :pushbroom 
    set_table_name :users_roles 

    belongs_to :user_account 
    belongs_to :user_role 
end 

class Pushbroom::UserAccount < ActiveRecord::Base 

    establish_connection :pushbroom 
    set_table_name :user_account 
    set_primary_key :id 

    has_many :users_roles_relationships 
    has_many :user_roles, :through => :users_roles_relationships, :source => :user_role 
end 

class Pushbroom::UserRole < ActiveRecord::Base 

    establish_connection :pushbroom 
    set_table_name :user_role 
    set_primary_key :id 

    has_many :users_roles_relationships 
    has_many :user_accounts, :through => :users_roles_relationships, :source => :user_account 
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 

由於一噸人幫助我得到這個火車繼續前行!我所有的測試都通過了,它似乎正在工作,但如果您發現有問題,請繼續通知我。

謝謝! 傑拉德

0

嘗試做一些手動保存在各個地方創建的對象,如create_pushbroom_user_account(pb_user)方法。依靠「自動保存」系統,過去我遇到過一些問題。

+0

我已經嘗試過保存每一步,它是100%成功,直到我到達user_roles。不管我如何賦值,甚至直接插入SQL(connection.execute/insert/etc),都會導致同樣的錯誤。這幾乎是關係配置的方式,但我已經完成了100次,這不是火箭科學:/感謝評論! – Gerald 2011-04-12 20:31:24