User 模型中的父子关系(自联接)

Jef*_*eff 4 ruby-on-rails

在 Rails 中,我有这个 User 模型:

class User < ActiveRecord::Base
  enum role: [:adult, :child, :admin]
  after_initialize :set_default_role, :if => :new_record?

  # belongs_to :spouse, :foreign_key => :spouse_id, :class_name => 'User', :inverse_of => :spouse 

  def set_default_role
    self.role ||= :adult
  end

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


  def marry(user)
    self.spouse = user
    user.spouse = self
  end
end
Run Code Online (Sandbox Code Playgroud)

我通过这次迁移添加了配偶:

class AddFieldsToUser < ActiveRecord::Migration
  def change
    # for marriages
    add_column :users, :spouse_id, :integer, index: true
  end
end
Run Code Online (Sandbox Code Playgroud)

并且效果很好(尽管我的逆函数从未起作用# belongs_to :spouse, :foreign_key => :spouse_id, :class_name => 'User', :inverse_of => :spouse )。我现在正在尝试通过“孩子 - 父母”关系进行另一个自我加入。一个父母可以有很多孩子,一个孩子可以有(很多/两个)父母。这是我想出的迁移:

class CreateParentalRelationships < ActiveRecord::Migration
  def change
    create_table :parental_relationships do |t|
      t.references :parent, index: true
      t.references :child
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我将它添加到模型中:

  has_many :children, :through => :parental_relationships, class_name: "User"
  has_many :parents, :through => :parental_relationships, class_name: "User"
Run Code Online (Sandbox Code Playgroud)

但该关系因以下错误而无效:

[7] pry(main)> u = User.find(3)
  User Load (0.0ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = ? LIMIT 1  [["id", 3]]
=> #<User id: 3, email: ...>

[8] pry(main)> u.children
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :parental_relationships in model Us
er

[9] pry(main)> u.parent
NoMethodError: undefined method `parent' for #<User:0x5e52eb0>
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activemodel-4.1.8/lib/active_model/attribute_methods.rb:435:in
 `method_missing'

[10] pry(main)> u.parents
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :parental_relationships in model Us
er
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/reflection.rb:690:in `che
ck_validity!'

[11] pry(main)> u2.children
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :parental_relationships in model Us
er
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/reflection.rb:690:in `che
ck_validity!'
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

max*_*max 6

建立父子关系需要一些麻烦。

class ParentalRelationship < ActiveRecord::Base
  belongs_to :parent, class_name: 'User'
  belongs_to :child, class_name: 'User'
end
Run Code Online (Sandbox Code Playgroud)
class User < ActiveRecord::Base
  has_many :parent_relationships,
          foreign_key: 'child_id',
          class_name: 'ParentalRelationship'

  has_many :child_relationships,
          foreign_key: 'parent_id',
          class_name: 'ParentalRelationship'

  has_many :parents,
          through: :parent_relationships,
          class_name: 'User'

  has_many :children,
          through: :child_relationships,
          class_name: 'User'

  has_and_belongs_to_many :marriages
  belongs_to :current_marriage, class_name: 'Marriage'

  def marry(spouse)
    marriage = Marriage.create(users: [self, spouse])
    marriage.users.each { |u| u.update(current_marriage: marriage ) }
    marriage
  end

  def spouse
    return nil unless current_marriage
    current_marriage
      .users.where.not('marriages_users.user_id' => id).first
  end

  def birth(child)
    child.parents << self
    child.parents << spouse if spouse
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,我们需要将关系设置为ParentalRelationship两次,因为我们需要告诉 rails 应该为每种类型的关系(用户是父级还是子级)查看哪个外键。


由于在现代,人们实际上可以结过几次婚,因此我们需要一个婚姻模型和一个用于 users_marriages 的连接表。

class Marriage < ActiveRecord::Base
  has_and_belongs_to_many :users
  validates :users, length: { minimum: 2, maximum: 2 }
end
Run Code Online (Sandbox Code Playgroud)
rails g migration CreateUsersMarriagesJoinTable users marriages
Run Code Online (Sandbox Code Playgroud)

具有规范的示例应用程序:https : //github.com/maxcal/sandbox/tree/31614819