如何在模型和表单构建器中使用外键?

时间:2012-06-08 08:16:37

标签: ruby-on-rails ruby-on-rails-3 simple-form rails-models

我有两个模型:UserLocation,如下所示:

class User < ActiveRecord::Base
  attr_accessible :location, :password, :user_name, :password_confirmation

  validates :location, :user_name, :presence => true
  validates :password, :presence => true, :confirmation => true

  has_one :location, :foreign_key => 'location'

end

class Location < ActiveRecord::Base
  attr_accessible :loc_id, :loc_name

  belongs_to :user, :foreign_key => 'loc_id'
end

您可以看到我对模型使用自定义foreign_key。我使用表单构建器来构建用户注册表单,但是当我提交数据时,会发生错误:

Location(#2170327880) expected, got String

我使用simple_form来构建表单,相关代码是:

= f.input :location, :collection => Location.all.collect {|c| [c.loc_name, c.loc_id]}

如何解决此问题?或者我必须使用location_id这样的默认foreign_key进行关联吗?

感谢。

更新

当我将location模型中的User字段重命名为loc_id并删除此:foreign_key时:

class User < ActiveRecord::Base
  attr_accessible :loc_id, :password, :user_name, :password_confirmation

  validates :loc_id, :user_name, :presence => true
  validates :password, :presence => true, :confirmation => true

  has_one :location, :foreign_key => 'location'

end

class Location < ActiveRecord::Base
  attr_accessible :loc_id, :loc_name

  belongs_to :user
end

工作正常。但我仍然想知道如何关联UserLocation模型。

P.S。我使用Location模型存储国家/地区代码和国家/地区名称,该名称永远不会按User更新。

4 个答案:

答案 0 :(得分:1)

看起来你在滥用外键。在用户模型中,您应该只有has_one :location,并且位置模型应该具有user_id属性。在位置模型中,您只需要编写belongs_to :user。外键始终是另一个(外部)表的索引。

答案 1 :(得分:1)

听起来你真的想拥有

class User < ActiveRecord::Base
  belongs_to :location
end

class Location < ActiveRecord::Base
  has_many :users
end

这意味着用户拥有location_id列。如果您以相反的方式执行操作(位置上的user_id列),则给定位置只能与一个用户相关联。 rails方式是位置表中id列的用户'点'location_id。如果您希望它指向不同的列,请使用:primary_key选项(如果您希望将用户列调用为location_id之外的其他内容,则为:foreign_key选项)

就表单而言,你不能f.select :location - 表单不知道如何传输这样复杂的对象。在这些情况下,您需要设置表单以控制location_id属性,即

= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.id]}

如果您沿着路线找到位置ID列,请参阅位置上的loc_id列,那么您需要将其更改为

= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.loc_id]}

就个人而言,如果你刚开始使用rails,我会坚持使用默认值

答案 2 :(得分:0)

class User < ActiveRecord::Base
  # stuff

  has_one :location    
end

class Location < ActiveRecord::Base
  # more stuff

  belongs_to :user
end

答案 3 :(得分:0)

如果您最终要做的是选择具有相同位置的所有用户,您可能希望以稍微不同的方式设置模型。现在,因为每个用户在位置表中都有自己的位置记录,所以最终会有重复的位置,您必须找到所有这些位置以获取唯一位置并从中提取user_id。

而是这样做

class User < ActiveRecord::Base
   has_one :placement
   has_one :location, through: :placement
end

class Placement < ActiveRecord::Base
    belongs_to :user
    belongs_to :location
end

class Location < ActiveRecord::Base
    has_many :placements
    has_many :users, through: :placements
end

。至于迁移,Placement应该有:user_id和:location_id。您可以删除当前位置中的:user_id。此代码所说的是我们有很多用户,而且我们有许多独特的位置,我们通过创建展示位置将用户放在不同的位置,这表示位于以下位置的用户:user_id位于:location_id。另外,不要忘记添加一行

add_index :placements, [:user_id, :location_id], unique: true

这样您就无法将用户置于多个位置。

编辑:忘记添加:您只需获取位置记录并调用location.users即可获取某个位置的所有用户