在ruby中连接它们之间的对象的最佳实践

时间:2011-10-28 13:50:38

标签: ruby

我无法找到一种很好的方法来实现导航rails在纯ruby脚本中的对象的rails行为。

假设我有一个类Parent的对象,它具有类Child对象数组的访问器,我操作Child对象时,我可以轻松地获取Parent,如下所示:

class Parent
  attr_accessor :children

  def initialize
    @children = Array.new
  end
end

class Child
end

parent = Parent.new
first_child = Child.new
second_child = Child.new
parent.children << [ first_child, second_child ]

a_child = parent.children.first

get_parent_from_child = a.child.parent

我感兴趣的部分当然是我试图获得父母的最后一行&#34;来自其中一个孩子的对象。

我怎样才能轻松,干净地实施?

我正在考虑为子对象添加一个访问器,但我不确定每次将子对象附加到父对象时如何确保设置此值。

在ruby中有一种简单而干净的方法吗?

提前致谢。

3 个答案:

答案 0 :(得分:2)

您无需完全公开您所知道的children,完全控制对您数据的访问权限没有任何问题。

class Parent
  def initialize
    @children = [ ]
  end

  # You get a shallow copy of the children, you can
  # change the individual children but not the tree
  # structure.
  def children
    @children.dup
  end

  # We take ownership of the children when you add them.
  def add_children(*kids)
    kids.each { |k| k.parent = self }
    @children += kids
  end

  def remove_children(&block)
    @children.delete_if(&block)
  end
end

# This would probably have some sort of payload and
# a sensible "==" implementation.
class Child
  attr_reader :parent
  def parent=(p)
    raise StandardError => 'Not allowed to change parents!' if @parent
    @parent = p
  end
end

然后child.parent工作正常,如果你想删除孩子,你会告诉家长要删除哪些:

# Remove the children with even payloads.
parent.remove_children { |c| c.payload % 2 == 0 }

# Remove the children with odd payloads and copy them.
odds = [ ]
parent.remove_children do |c|
  kill_it = c.payload % 2 != 0
  odds << Child.new(c.payload) if(kill_it)
  kill_it
end

答案 1 :(得分:1)

为类中的子项编写一个自己的访问器Parent,在其中为添加到数组的每个子项设置父属性。从阵列中删除子项时,请执行相反的操作。我就是这样做的。

答案 2 :(得分:1)

您可以使用自定义容器类从Rails实现has_many行为,就像Rails一样。

class Parent
  attr_reader :children

  def initialize
    @children = ChildCollection.new(self)
  end
end

class Child
  attr_accessor :parent
end

class ChildCollection
  def initialize parent
    @children = []
    @parent = parent
  end

  def new
    child = Child.new
    child.parent = @parent
    @children << child
    child
  end

  def << child
    child.parent = @parent
    @children << child
    self
  end
end

一些将子项添加到父项的示例代码:

parent = Parent.new
child1 = parent.children.new
child2 = Child.new
child3 = Child.new
parent.children << child2 << child3

puts "Parent is: #{parent.object_id}"
puts "Child1's parent is: #{child1.parent.object_id}"
puts "Child2's parent is: #{child2.parent.object_id}"
puts "Child3's parent is: #{child3.parent.object_id}"

您可能想要使用其他一些有用的方法,例如removeeach(这样您就可以ChildCollection包含Enumerable模块并获取所有很酷的内容随之而来)但这应该足以让你开始。