Rails - 覆盖has_one上的主键

时间:2009-09-10 17:57:09

标签: ruby-on-rails

我有以下关联,基本上我想通过userid链接而不是对象的id。

class Tweet < ActiveRecord::Base
  has_one :user_profile, :primary_key => 'userid', :foreign_key => 'twitter_userid' 

class UserProfile < ActiveRecord::Base
  belongs_to :tweet, :foreign_key => 'userid'

然而,以下规范失败,因为twitter_userid被重置为对象的id

it "should have the user's twitter id set on their user profile" do
   t = Tweet.new(:twitter_id => 1,
                  :status => 'Tester', 
                  :userid => 'personA',
                  :user_profile => UserProfile.new(:twitter_userid => 'personA', :avatar => 'abc'))
   t.save!
    t.user_profile.twitter_userid.should == 'personA'
 end

应该在用户个人资料中设置用户的Twitter ID

expected: "personA",
    got: 216 (using ==)

但是,以下内容确实通过了:

 it "should return the correct avatar after being saved" do
   t = Tweet.new(:twitter_id => 1,
                  :status => 'Tester', 
                  :userid => 'personA', 
                  :user_profile => UserProfile.new(:twitter_userid => 'personA', :avatar => 'abc'))
   t.save!

   t.user_profile.avatar.should == 'abc'
 end

如何强制它使用userid而不是id?

由于

4 个答案:

答案 0 :(得分:1)

cite@antiope:/tmp/foo$ script/console
Loading development environment (Rails 2.3.4)
>> t = Tweet.new(:twitter_id => 1,
?>                   :status => 'Tester', 
?>                   :userid => 'personA',
?>                   :user_profile => UserProfile.new(:twitter_userid => 'personA', :avatar => 'abc'))
=> #<Tweet id: nil, twitter_id: 1, status: "Tester", userid: "personA", created_at: nil, updated_at: nil>
>> Tweet.set_primary_key :userid
=> nil
>> t.save
  Tweet Create (0.4ms)   INSERT INTO "tweets" ("created_at", "updated_at", "userid", "twitter_id", "status") VALUES('2009-09-10 20:19:36', '2009-09-10 20:19:36', 'personA', 1, 'Tester')
  UserProfile Create (0.1ms)   INSERT INTO "user_profiles" ("twitter_userid", "created_at", "updated_at", "avatar") VALUES('personA', '2009-09-10 20:19:36', '2009-09-10 20:19:36', 'abc')
=> true
>> Tweet.set_primary_key :id
=> nil

如果您只需要在一个地方重新定义主键,那么在保存模型之前一段时间修改模型可能是一个可接受的解决方案(我没有测试修改Tweet类是否只影响当前控制器或所有操作)。不过,这只是我认为的解决方法。

答案 1 :(得分:1)

这里有两件事。我想你已经切换了:has_one和:belongs_to声明。

:belongs_to出现在具有外键的模型中。 :has_one出现在所引用的模型中(如果它只有一个,否则如果有很多行:belongs_to相同,当然它是has_many)。有关详细信息,请阅读here

首先,您需要指定(否决)模型的主键。在这里,我假设一个用户可以有很多推文,而不只是一个(否则由:has_one替换。)

class UserProfile
  set_primary_key :userid
  has_many :tweets 
end

然后您需要调整:has_one声明:

class Tweet
  belongs_to :user_profile, :foreign_key => :userid
end

然后,其次,一旦您的关系设置正确,就无需在创建时分配:user_profile:userid。您可以创建新的UserProfile,并且外键会自动更正,或者您分配现有个人资料的userid

希望这有帮助。

答案 2 :(得分:0)

如果数据库中的主键未被称为id,那么您希望执行以下操作:

class Tweet < AR:B
  set_primary_key "userid" 
end 

但是,我不确定我完全理解这个问题。您是否有理由想要超越铁路惯例?

答案 3 :(得分:0)

我认为这可能是最实用的方法。我认为在Rails中不可能: http://compositekeys.rubyforge.org/