Ruby (Rails) Делегировать атрибуты методу другой модели? - PullRequest
19 голосов
/ 16 января 2011

-EDIT-

После прочтения о методе Delegate из первого ответа мой вопрос заключается в том, можно ли делегировать два разных метода другому отдельному методу.

IE: Iв настоящее время есть: @ photo.attachment.file.url и @ photo.attachment.height и @ photo.attachment.width

Я хотел бы иметь возможность получить доступ ко всем этим через @ photo.file.url, @ photo.file.height, @ photo.file.width.

Причина синтаксиса в том, что Attachment представляет собой модель, которая использует Paperclip для управления файлами, Paperclip генерирует метод .file (модельназывается Attachment, модель использует Paperclip has_attached_file :file.мое приложение в Rails 3):

У меня есть две модели: Фото имеет вложение.

Вложение имеет атрибуты "высота" и "ширина", а также метод "файл" (из Paperclip).

Так что по умолчанию яможет получить доступ к битам модели Attachment следующим образом:

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

Теперь в своем классе фотографий я создал этот метод:

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

Итак, теперь я могу просто использовать:

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

Мой вопрос в том, что я смог указать photo.attachment.file на photo.file, но могу ли я также сопоставить высоту и ширину с photo.file, чтобы ради согласованности я мог получить доступ катрибуты height и width через photo.file.height и photo.file.width?

Возможна ли такая вещь, и если да, то как она выглядит?

Ответы [ 4 ]

53 голосов
/ 20 января 2011

Итак, вы спрашиваете, что

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

Вы не можете решить эту проблему с делегатами, потому что хотите, чтобы file означало разные вещи в зависимости от того, что следует дальше. Чтобы достичь этого, вам нужно будет снова открыть скрепку, которую я бы не рекомендовал (потому что я считаю, что API хорош, как есть).

Единственный способ решить эту проблему - добавить исключить уровень file. Вот так:

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

Это можно решить, используя delegate для каждого из требуемых методов.

Итак, вы пишете

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

Надеюсь, это поможет.

5 голосов
/ 16 января 2011

Вы можете использовать метод Rails 'делегат'. Посмотрите на мой ответ на этот вопрос:

Какой способ выполнения этой команды более похож на Ruby?

1 голос
/ 20 января 2011

Самый простой способ, который приходит на ум, - это делегировать метод url во вложении в файл:

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

Таким образом, вы можете вызвать photo.attachment.url, photo.attachment.width, photo.attachment.Высота, которая для меня кажется довольно последовательной.При желании вы можете добавить псевдоним вложение в файл - таким образом вы получите точные имена методов, которые вы запрашивали (photo.file.width, photo.file.url), но я бы не советовал, потому что это кажется запутанным (вызов вложения"файл").

class Photo < ActiveRecord::Base
  def file
    attachment
  end
end
0 голосов
/ 04 октября 2018

С обычным Ruby вы можете использовать Forwardable :

require 'forwardable'

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