2011-08-21 53 views
2

在我的应用程序,Photo has_and_belong_to_many :land_usesRuby/Rails:创建一个对其子项实例进行操作的类方法?

我在Photo模型这个辅助方法:

def land_use_list 
    land_uses.map(&:name).join(', ') 
end 

这在我看来是一个代码味道(得墨忒耳),但我一直无法弄清楚如何将其移至LandUse模型。我想要做的是一样的东西:

class LandUse < ActiveRecord::Base 
    ... 
    def self.list 
    self.map(&:name).join(', ') 
    end 
    ... 
end 

这样而不是调用photo.land_use_list我可以打电话给photo.land_uses.list

但是,这不起作用,因为它被称为反对类,而不是被称为针对属于特定照片的范围实例。

有没有办法做我在想什么?而且,更一般地说,您如何在应用程序中处理类似这样的问题?是否将清单代码移到LandUse模型的正确方法,还是您会推荐不同的东西?

回答

1

首先,我不认为这违反了德米特法本身。对于调用属性上的一个方法创建临时变量的对象,您有一个方法,然后对该临时变量执行操作。

如果你完全从不同的课程中完成这将违反德米特法。例如,

class User 
    def names_of_lands_ive_known 
    photos.map(:land_uses).map(:name).join ', ' 
    end 
end 

事实上,它只是很好的信息隐藏。但是,如果你想写photo.land_uses.names,你可以添加一个扩展到协会去做你想做的事情。

class Photo 
    has_and_belong_to_many :land_uses do 
    def names_as_list_string 
     all.map(:name).join ', ' 
    end 
    end 
end 

有关关联扩展的更多信息,请查看docs

符合德米特法则的最好方法是做或多或少的你在做什么,因为通过在Photo上添加你的方法,这意味着与Photo交互的方法也不需要了解LandUse类,只是该照片有一个方法返回一个土地用途名称的字符串。

+0

真棒建议,我不知道关联扩展。也感谢你为我清理德米特问题。我一直在想,照片只知道他们有土地用途,他们不应该关心土地如何使用自己的格式。但是我看到你的观点只是与它所具有的内容进行交互。这非常有帮助! – Andrew

0

您可以使用:

class LandUse 
    def self.list_for_photo(id) 
    LandUse.find_by_photo_id(id).join(', ') 
    end 

    def to_s 
    self.name 
    end 
end 

希望它能帮助!

+0

目标是创建一个一致的帮助方法,从LandUse类返回它们的名称列表,而不是一组土地使用对象。这个建议并不能帮助我做到这一点。我熟悉to_s,它可能会保存一条命令,但是想法是能够指定land_uses,我想将它们的列表作为连接字符串而不是实例数组返回。 – Andrew

+0

我编辑所以它更适合您的需求:) – Cydonia7

0

我不是一个Rails应用程序的前面,但我相信

photo.land_uses 

与回报LandUse对象

数组所以你只需要向下移动地图到阵列,如:

photo.land_uses.map(&:name).join(', ') 

这是你最初的 - 只是在你的其他模型。我想你可能是对的,这意味着Photo知道太多关于LandUse,因此我会将其移出。

+0

好吧,所以我应该将此方法移动到LandUse - 但问题是,如何?我无法在类方法中调用.each,并且调用self方法不允许我访问从照片调用的作用域实例。你知道如何解决这个问题吗? – Andrew

+0

我可能将控制器中的实现留在控制器中,并将其移入私有方法中,因此我不必多次输入'.map(&:name).join(',')'。如果你想要一个更具体的解决方案,那么也许扩展ActiveRecord,但我不知道从哪里开始寻找猴子修补你的方法 –

相关问题