Rails模型具有自身的has_many关联

40

我有一个事件模型。事件可以有父事件,从模型中的一个列(parent_event_id)设置。我需要在模型上能够执行has_many:event,这样我就可以只做例如event.child_eventevent.parent_event。但是我的搜索效果并不好。

我的模型:

class Event < ActiveRecord::Base
    attr_accessible :days_before, :event_name, :event_date, :list_id, :recipient_email, :recipient_name, :parent_event_id, :is_deleted, :user_id

    belongs_to :user
    has_many :event_email
    has_many :event
end

我的模式:

create_table "events", :force => true do |t|
    t.datetime "event_date"
    t.integer  "days_before"
    t.string   "recipient_email"
    t.integer  "list_id"
    t.string   "recipient_name"
    t.datetime "created_at",                         :null => false
    t.datetime "updated_at",                         :null => false
    t.integer  "user_id"
    t.string   "event_name"
    t.integer  "parent_event_id"
    t.boolean  "is_deleted",      :default => false
end
6个回答

75

这是一个自引用模型,你可以尝试类似以下的操作:

class Event < ActiveRecord::Base
  belongs_to :parent, :class_name => "Event", :foreign_key => "parent_event_id"
  has_many :child_events, :class_name => "Event", :foreign_key => "child_event_id"
end

这样,您可以调用 @event.parent 获取一个 ActiveRecord Event 对象,@event.child_events 获取一个 ActiveRecord Event 对象的集合。


1
belongs_tohas_many 中我们需要同时使用 foreign_key 吗? - r3b00t
我们可以使用 accepts_nested_attributes_for :child_events, allow_destroy: true 吗? - Tashi Dendup
1
此解决方案将父 ID 设置为“child_event_id”字段。如果我对两个关系都使用“parent_event_id”作为外键,则它按预期工作。 - Cbas

4
您需要将您的has_many更改为以下内容:
has_many :parent_events, class_name: 'Event'
has_many :child_events, ->(event) { where parent_event_id: event.id }, class_name: 'Event'

这是来自Rails 4文档的内容,链接如下: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html 具体地,这里讲到了“自定义查询”的部分。这应该可以帮助你实现你所需要的功能。我没有在本地试过,但这与我之前做的一个足球竞猜应用程序类似。
希望这可以帮到你。

2
Rails已经有一个提供嵌套树结构的gem,即ancestry。在这种情况下,使用它会是最好的选择:

https://github.com/stefankroes/ancestry

你将能够访问以下方法:
event.parent
event.children
event.siblings

2

1
我发现在Rails 5中,默认情况下belongs to已变为强制性,因此无法保存我的模型实例...在建议解决方案的第一行添加optional修饰符可以解决此问题...
class Event < ActiveRecord::Base
  belongs_to :parent, :class_name => "Event", :foreign_key => "parent_event_id", optional: true
  has_many :child_events, :class_name => "Event", :foreign_key => "parent_event_id"
end

0

我不确定这对于Rails 6来说是否是新的,但是Rails Guide关于Active Record Associations 有一个关于自连接的部分,提供了一个更简洁的解决方案:

class Event < ApplicationRecord
  has_many :children, class_name: "Event", foreign_key: "parent_id"
 
  belongs_to :parent, class_name: "Event", optional: true
end

请注意,只有子事件需要parent_id。在belongs_to关联中,可选项是必要的,以允许您保存模型,因为从Rails 5开始,belongs_to是强制性的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接