Ruby (Rails) 将属性委托给另一个模型的方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4703357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:07:07  来源:igfitidea点击:

Ruby (Rails) Delegate attributes to another model's method?

ruby-on-railsruby-on-rails-3aliasshortcut

提问by Andrew

-EDIT-

-编辑-

After reading about the Delegate method from the first answer, my question is this, is it possible to delegate two different methods to another single method.

从第一个答案中阅读了 Delegate 方法后,我的问题是,是否可以将两种不同的方法委托给另一种方法。

IE: I currently have: @photo.attachment.file.url, and @photo.attachment.height, and @photo.attachment.width

IE:我目前有:@photo.attachment.file.url、@photo.attachment.height 和@photo.attachment.width

I'd like to be able to access all of these via @photo.file.url, @photo.file.height, @photo.file.width.

我希望能够通过@photo.file.url、@photo.file.height、@photo.file.width 访问所有这些。

The reason for the syntax is Attachment is a model that uses Paperclip to manage files, Paperclip is generating the .file method (the model is called Attachment, the model uses Paperclip's has_attached_file :file).

语法的原因是Attachment是一个使用Paperclip管理文件的模型,Paperclip正在生成.file方法(该模型称为Attachment,模型使用Paperclip的has_attached_file :file)。

-ORIGINAL QUESTION-

-原始问题-

I was wondering about aliasing methods and attributes in Ruby (I think this is a general ruby question, although my application is in Rails 3):

我想知道 Ruby 中的别名方法和属性(我认为这是一个通用的 ruby​​ 问题,尽管我的应用程序在 Rails 3 中):

I have two models: Photo has_one Attachment.

我有两个模型:照片 has_one 附件。

Attachment has "height" and "width" attributes, and a "file" method (from Paperclip).

附件具有“高度”和“宽度”属性,以及“文件”方法(来自 Paperclip)。

So by default I can access bits of the Attachment model like so:

所以默认情况下,我可以像这样访问附件模型的位:

photo.attachment.width # returns width in px
photo.attachment.height # returns height in px
photo.attachment.file # returns file path
photo.attachment.file.url #returns url for the default style variant of the image
photo.attachment.file.url(:style) #returns the url for a given style variant of the image

Now, in my photo class I have created this method:

现在,在我的照片类中,我创建了这个方法:

def file(*args)
    attachment.file(*args)
end

So, now I can simply use:

所以,现在我可以简单地使用:

photo.file # returns file path
photo.file.url # returns file url (or variant url if you pass a style symbol)

My question is, I was able to direct photo.attachment.fileto just photo.file, but can I also map height and width to photo.file, so that, for the sake of consistency, I could access the height and width attributes through photo.file.heightand photo.file.width?

我的问题是,我能够直接photo.attachment.file指向photo.file,但我也可以将高度和宽度映射到photo.file,以便为了一致性起见,我可以通过photo.file.height和访问高度和宽度属性photo.file.width

Is such a thing possible, and if so what does it look like?

这样的事情可能吗,如果有的话,它看起来像什么?

回答by nathanvda

So what you are asking is that

所以你要问的是

photo.file       --> photo.attachment.file
photo.file.url   --> photo.attachment.file.url
photo.file.width --> photo.attachment.width

You can't solve this with delegates, because you want that fileto mean different things based on what follows next. To achieve this you would need to reopen paperclip, which i would not recommend (because i believe the api is good the way it is).

你不能用委托来解决这个问题,因为你希望file根据接下来的内容来代表不同的东西。要实现这一点,您需要重新打开回形针,我不推荐这样做(因为我相信 api 就这样很好)。

The only way i can think of to solve this, is to add eliminate the filelevel too. Like so:

我能想到的解决这个问题的唯一方法就是添加消除file级别。像这样:

photo.width      --> photo.attachment.width
photo.file       --> photo.attachment.file
photo.url        --> photo.attachment.file.url

This you could then solve by using a delegatefor each of the wanted methods.

然后,您可以通过delegate对每个想要的方法使用 a来解决这个问题。

So you write

所以你写

class Photo
  delegate :width, :height, :file, :to => :attachment
  delegate :url,   :to => :'attachment.file'
end

Hope this helps.

希望这可以帮助。

回答by monocle

You can use Rails 'delegate' method. Have a look at my answer for this question:

您可以使用 Rails 的“委托”方法。看看我对这个问题的回答:

What is a more Ruby-like way of doing this command?

执行此命令的更像 Ruby 的方式是什么?

回答by psyho

The simplest way that comes to mind is to delegate url method in attachment to file:

想到的最简单的方法是将附件中的 url 方法委托给文件:

class Attachment < ActiveRecord::Base
  delegate :url, :to => :file
end

This way you can call photo.attachment.url, photo.attachment.width, photo.attachment.height, which for me seems pretty consistent. You could optionally alias attachment to file - this way you'd get the exact method names you asked for (photo.file.width, photo.file.url), but I would not recommend that, because it seems confusing (calling an attachment "file").

通过这种方式,您可以调用 photo.attachment.url、photo.attachment.width、photo.attachment.height,这对我来说似乎非常一致。您可以选择将附件作为文件的别名 - 这样您就可以获得您要求的确切方法名称(photo.file.width,photo.file.url),但我不建议这样做,因为它看起来令人困惑(调用附件“文件”)。

class Photo < ActiveRecord::Base
  def file
    attachment
  end
end

回答by Damien Roche

With plain Ruby you can use Forwardable:

使用普通的 Ruby,您可以使用Forwardable

require 'forwardable'

class RecordCollection
  attr_accessor :records
  extend Forwardable
  def_delegator :@records, :[], :record_number
end