简体   繁体   English

Rails 模型关联,has_many :through 和 has_one 具有相同的模型

[英]Rails model associations, has_many :through and has_one with the same model

I have two models: User and State.我有两个模型:用户和状态。 The state model has records for each of the 50 states in the United States.州模型拥有美国 50 个州中每一个州的记录。

I would like each User to have two attributes: one "home" state, and many states to "visit".我希望每个用户都有两个属性:一个是“家”状态,另一个是“访问”状态。

I know I have to set up some sort of model associations to achieve this, but not sure what the best approach is.我知道我必须建立某种模型关联来实现这一点,但不确定最好的方法是什么。

Here's what I have so far, but I know there must be something wrong with have has_many and has_one association to the same model.这是我到目前为止所拥有的,但我知道将 has_many 和 has_one 关联到同一模型肯定有问题。

#user.rb
class User < ActiveRecord::Base
   has_many :visits
   has_many :states, :through => :visits
   has_one :state
end

#visit.rb
class Visit < ActiveRecord::Base
   belongs_to :user
   belongs_to :state
end

#state.rb
class State < ActiveRecord::Base
   has many :visits
   has many :users, :through => :visits 
   belongs_to :user
end
   

Any suggestions?有什么建议?

In my opinion what you already have is almost right, except you would store the home state foreign key on the user like thus:在我看来,您已经拥有的几乎是正确的,除非您将主状态外键存储在用户上,如下所示:

# user.rb
class User < ActiveRecord::Base
  belongs_to :state
  has_many :visits
  has_many :states, through: visits
end

# visit.rb
class Visit < ActiveRecord::Base
  belongs_to :user
  belongs_to :state
end

# state.rb
class State < ActiveRecord::Base
  has_many :visits
  has_many :users, through: :visits
end

You would then access the home state like thus:然后,您将像这样访问主状态:

u = User.first
u.state

And the visited states, like thus:和访问过的状态,如下所示:

u = User.first
u.states

For programming clarity, you can rename your relations:为了编程清晰,您可以重命名您的关系:

# user.rb
class User < ActiveRecord::Base
  belongs_to :home_state, class_name: "State"
  has_many :visits
  has_many :visited_states, class_name: "State", through: visits
end

# state.rb
class State < ActiveRecord::Base
  has_many :residents, class_name: "User"
  has_many :visits
  has_many :visitors, class_name: "User", through: :visits
end

Your domain model would make more sense:您的域模型会更有意义:

u = User.first
u.home_state
u.visited_states

s = State.first
s.residents
s.visitors

I expect you'll probably want to store additional information about the visit, so keeping the HMT join table for the Visit model will allow you to do this, rather than going with a HABTM relation.我预计您可能希望存储有关访问的其他信息,因此保留Visit模型的 HMT 连接表将允许您执行此操作,而不是使用 HABTM 关系。 You could then add attributes to the visit:然后,您可以向访问添加属性:

# xxxxxxxxxxxxxxxx_create_visits.rb
class CreateVisits < ActiveRecord::Migration
  def change
    create_table :visits do |t|
      t.text :agenda
      t.datetime commenced_at
      t.datetime concluded_at
      t.references :state
      t.references :user
    end
  end
end

I would like each User to have two attributes: one "home" state, and many states to "visit".我希望每个用户都有两个属性:一个是“家”状态,另一个是“访问”状态。

In your models, a state may only be home to one user ( belongs_to ).在您的模型中,一个州可能只belongs_to一个用户 ( belongs_to )。

The correct semantics would be正确的语义是

class User < AR::Base
  belongs_to :home_state, :class_name => "State", :foreign_key => "home_state_id", :inverse_of => :users_living
  has_and_belongs_to_many :visited_states, :through => :visits
  # ...
end

class State < AR::Base
  has_many :users_living, :class_name => "User", :inverse_of => :home_state
  # ...
end

You can't have a has_many and has_one relationship on a single model, in this case state.您不能在单个模型上拥有 has_many 和 has_one 关系,在本例中为 state。 One solution is to:一种解决方案是:

create a static model of states, they do not need to be a database model, they could be a static variable on the state model: US_STATES = {'1' => 'AK', '2' => 'AL', etc} or you could use fixtures to load a table of states into the database (more complicated because you need to use a rake task or the db:seed task to load the fixtures into the db, but nice because you can use active record to manage the model).创建状态的静态模型,它们不需要是数据库模型,它们可以是状态模型上的静态变量: US_STATES = {'1' => 'AK', '2' => 'AL', etc}或者因为你需要使用一个rake任务或数据库,你可以使用fixture状态的表加载到数据库中(更复杂:种子任务加载夹具进入分贝,但好的,因为你可以使用活动记录管理该模型)。

then you can provide a home_state_id on the user model that defines the home_state and the visits are simply a join between user_id and the state_id.然后您可以在定义 home_state 的用户模型上提供 home_state_id,访问只是 user_id 和 state_id 之间的连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM