-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.
IE: I currently have: @photo.attachment.file.url, and @photo.attachment.height, and @photo.attachment.width
I'd like to be able to access all of these via @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
).
-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):
I have two models: Photo has_one Attachment.
Attachment has "height" and "width" attributes, and a "file" method (from 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.file
to 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.height
and photo.file.width
?
Is such a thing possible, and if so what does it look like?
In Ruby, every object inherits from the Object class by default. That's why you get access to methods like puts , class & object_id . With composition a class creates (or is given) objects from another class… then it uses these objects to delegate work to them.
On the Profile side we use the delegate method to pass any class methods to the User model that we want access from our User model inside our Profile model. The delegate method allows you to optionally pass allow_nil and a prefix as well. Ultimately this allows us to query for data in custom ways.
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 file
to 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).
The only way i can think of to solve this, is to add eliminate the file
level too. Like so:
photo.width --> photo.attachment.width
photo.file --> photo.attachment.file
photo.url --> photo.attachment.file.url
This you could then solve by using a delegate
for each of the wanted methods.
So you write
class Photo
delegate :width, :height, :file, :to => :attachment
delegate :url, :to => :'attachment.file'
end
Hope this helps.
You can use Rails 'delegate' method. Have a look at my answer for this question:
What is a more Ruby-like way of doing this command?
The simplest way that comes to mind is to delegate url method in attachment to file:
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").
class Photo < ActiveRecord::Base
def file
attachment
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With