Ruby / Rails:创建一个对其子实例进行操作的类方法?

发布于 2024-11-30 19:26:51 字数 620 浏览 1 评论 0原文

在我的应用程序中,Photo has_and_belong_to_many :land_uses

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

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

这让我觉得有代码味道(demeter),但我无法做到找出如何将其移动到 LandUse 模型。我想做的是这样的:

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

这样我就可以调用 photo.land_uses.list 而不是调用 photo.land_use_list

但这不起作用,因为它是针对类调用的,而不是针对属于特定照片的作用域实例调用的。

有办法实现我的想法吗?更一般地说,您如何在应用程序中解决此类问题?将列表代码移至 LandUse 模型是否是正确的方法,或者您会推荐不同的方法吗?

In my app, Photo has_and_belong_to_many :land_uses

I have this helper method in the Photo model:

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

This strikes me as a code smell (demeter), but I haven't been able to figure out how to move it to the LandUse model. What I'd like to do is something like:

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

So that instead of calling photo.land_use_list I could call photo.land_uses.list.

But that doesn't work, because it gets called against the class instead of being called against the scoped instances belonging to a particular photo.

Is there a way to do what I'm thinking of? And, more generally, how do you approach issues like this in your app? Is moving the list code to the LandUse model the right approach, or would you recommend something different?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

萌吟 2024-12-07 19:26:51

首先,我认为这本身并不违反德墨忒尔定律。您有一个对象上的方法,该方法调用属性上的一个方法来创建临时变量,然后对该临时变量进行操作。

如果你是从完全不同的阶层做这件事,那就违反了德墨忒尔法则。例如

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

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

遵守德米特定律的最佳方法是或多或少地做你正在做的事情,因为通过在 Photo 上添加你的方法,这意味着与 Photo< 交互的方法/code>,也不需要了解 LandUse 类,只需该照片有一个返回土地用途名称字符串的方法即可。

First, I don't think this is violating the Law of Demeter per se. You have a method on an object that calls one method on an attribute to create a temporary variable, and then act on the temporary variable.

It would be a violation of the Law of Demeter, if you were doing this from a different class entirely. eg

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

As it is, it's just good information hiding. But, if you wanted to be able to write photo.land_uses.names, you could add an extension to the association to do what you want.

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

For more information on association extensions, check out the docs.

The best way to conform to the law of demeter is to do more or less what you are doing though, because by adding your method on Photo, it means that the methods that interact with Photo, don't also need to know about the LandUse class, just that photo has a method that returns a string of the names of land uses.

小鸟爱天空丶 2024-12-07 19:26:51

我不在 Rails 应用程序前面,但我相信

photo.land_uses

会返回一个 LandUse 对象数组

,因此您只需将地图向下移动到该数组,例如:

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

这就是您最初拥有的 - 就在您的其他型号。我认为你可能是对的,这意味着 PhotoLandUse 了解太多,因此我会将其移出。

I am not in front of a rails app but I believe

photo.land_uses

with return an Array of LandUse objects

So you just need to move your map down to that array like:

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

which is what you had originally - just in your other model. I think you may be right and it means that Photo knows too much about LandUse therefore I would move it out.

信愁 2024-12-07 19:26:51

您可以使用:

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

  def to_s
    self.name
  end
end

希望有帮助!

You can use :

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

  def to_s
    self.name
  end
end

Hope it helps !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文