in Rails using the Polymorphic version of Paperclip, the default saving technique means that files with the same name overwrite each other. Including the :id in the path and URL doesn't work as it just overwrites the earlier file with the old :id.
I've tried interpolations using a time-stamp, but it just looks for the current time when being shown the image (plus as I have multiple thumbnails it takes longer than a second, therefore the images have different stamps).
Paperclip.interpolates :uniqueid do |attachment, style|
Time.now.to_i.to_s
end
Also tried using a hex number, but it iterates through for each thumb, thus breaking as there's a new hex value each time.
Paperclip.interpolates :uniqueid do |attachment, style|
ActiveSupport::SecureRandom.hex(3)
end
As it's the Polymorphic version, and thus has it's own model, I don't know how to access the values from the parent model (in this case "Post").
Variations on the code below all throw up "undefined method" errors.
Paperclip.interpolates :user_id do |attachment, style|
current_user.id
end
Sorry if it seems a newbie question, but it's well document for the traditional Paperclip, but nothing is out there for the Polymorphic fork.
How about including :class in the :path for has_attached_file ?
has_attached_file :attachment,
:path => ":rails_root/attachments/:class/:id/:attachment/:basename.:extension",
:url => "downloads/:id/:title.:extension"
Related
I have a model of ThreesixtyViewer which also has a nested resource of the ThreesixtyViewerImage model. An image attribute is being saved via the paperclip gem - but I am having issues updating the file path how it's needed.
The images for each ThreesixtyViewer needs to be saved together within one directory that is associated with the specific viewer. For example:
/public/system/threesixty_viewer_images/12/large/filename.jpg
In this example, the 12 in the path would be the id of the specific threesixtyviewer - but I cannot find any examples with that functionality. If the ThreesixtyViewer had an ID of 57, then the path would look like so:
/public/system/threesixty_viewer_images/57/large/filename.jpg
threesixty_viewer.rb
belongs_to :article
has_many :threesixty_viewer_images, dependent: :delete_all
accepts_nested_attributes_for :threesixty_viewer_images, allow_destroy: true
threesixty_viewer_image.rb
belongs_to :threesixty_viewer
has_attached_file :image, styles: { small: "500x500#", large: "1440x800>" },
path: ':rails_root/public/system/:class/:VIEWER_ID/:size/:filename',
url: '/system/:class/:VIEWER_ID/:size/:filename'
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
I know the :path and :url attributes need to beupdated for the has_attached_file within the threesixty_viewer_image.rb - but I am unsure as to how I can get the id for the threesixty_viewer... for now I added a :VIEWER_ID in it's place.
Any help would be greatly appreciated! Thanks in advance for anyone who can lend an eye!
You can add any of the models attributes to that path for this object. I believe you can even go so far as adding anything that the method will respond to, so you can even create path helpers for returning specific strings (such as month it was saved, year, etc).
In your case, ThreesixtyViewerImage is a child model, your table should include a column for the parent model. In your case, that attribute is probably :threesixty_viewer_id
Here is what I think you need for setting that path on threesixty_viewer_image.rb:
has_attached_file :image,
styles: { small: "500x500#", large: "1440x800>" },
path: ":rails_root/public/system/:class/:threesixty_viwer_id/:size/:filename",
url: "/system/:class/:threesixty_viewer_id/:size/:filename"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
EDIT
Everything I said above is dead wrong. My apologies! What you need to use is a Paperclip::Interpolation. Here's a link
Here's what I did to make use:
Create a new file: config/initializers/paperclip_interpolators
Place something like this in that file:
Paperclip.interpolates :threesixty_viewer_id do |attachment, style|
attachment.instance.threesixty_viewer_id
end
Restart your application
Regenerate your paths/folders for the attachments. Here's a Link
Anytime you want another attribute in your path, just add another interpolator! Sorry again for misleading you before.
#colin_hagan is on the right path - I would suggest you look into Paperclip Interpolations:
#app/models/threesixty_viewer_image.rb
class ThreesixtyViewerImage < ActiveRecord::Base
belongs_to :threesixty_viewer
has_attached_file :image,
path: ":rails_root/public/system/:class/:threesixty_viewer_id/:size/:filename",
url: "/system/:class/:threesixty_viewer_id/:size/:filename"
Paperclip.interpolates :threesixty_viewer_id do |attachment, style|
attachment.instance.threesixty_viewer_id
end
end
Notice the double quotes, rather than single.
Double quotes should be used for interpolation - single quotes are for literal strings (I think).
Another thing I found some time back is the paperclip_defaults option -- allowing you to specify styles etc for any attachments:
#config/application.rb
...
config.paperclip_defaults = {
styles: { small: "500x500#", large: "1440x800>" }
}
These can be overridden in your respective models - it's just handy for me, as it means you don't have to explicitly define styles each time you have an attachment.
I have this (these) model(s)
Portfolio
-- PortfolioItem item
-- Image image
has_attachment :attachment
all with nice slugs and I would want the url of :attachment to reflect this organization, such as with a instance
photos/holiday_in_venice/ponte_vecchio (all slugs of the respective hierarchy)
would generate this url
photos(??)/holiday_in_venice(??)/:slug/:style.:extension
how would I access these antecessor objects during paperclip path/url creation?
currently I am only able to do
ponte_vecchio/small.png
You'll need to create custom interpolations. After that you are able define a :url and a :path.
Put a file called paperclip.rb in your config/initializers/ folder and do something like this:
Paperclip.interpolates :portfolio_slug do |attachment, style|
attachment.instance.portfolio_item.portfolio.title.parameterize
end
Paperclip.interpolates :portfolio_slug do |attachment, style|
attachment.instance.portfolio_item.title.parameterize
end
After that you can use those interpolations like that:
has_attached_file :attachment,
:path=>":rails_root/public/photos/:portfolio_slug/:item_slug/:style.:extension",
:url=>"/photos/:portfolio_slug/:item_slug/:style.:extension"
I am using paperclip for uploading images in my rails application.
I have 2 models 'Image' and 'Book' where one book can have many Images and image belongs_to Book.
In my 'images' table, I have 4 columns:
id
book_id
data_file_path
data_file_name
column 'data_file_path' stores the path of the image and column 'data_file_name' stores the image name and extension
In my image.rb file, I have the following lines of code:
has_attached_file :data, :path => "http://www.test.org/book/book_images/:data_file_path/:book_id/:style/:basename.:extension",
:url => "http://www.test.org/book/book_images/:data_file_path/:book_id/:style/:basename.:extension"
Notice the ':data_file_path' in the code above.
In my view, when i do <%=image.data.url(:thumb)%> i get the following path:
http://www.test.org/book/book_images/data_file_path/9124/thumb/1897_EK91_201107.jpg
Instead of retrieving the data_file_path value from the d-base, it's displaying the variable name.
How to I get the data_file_path value in the url.
Thanks a lot for your precious help. I have struggling with that since a while now.
Ah, I finally figured it out. I needed to use Paperclip.interpolates.
I added the following in config/initializers/paperclip.rb file
Paperclip.interpolates :data_file_path do |attachment, style|
attachment.instance.data_file_path
end
Then just add 'data_file_path' to the path in image.rb:
has_attached_file :data, :path => "http://www.test.org/book/book_images/:data_file_path/:book_id/:style/:basename.:extension",
:url => "http://www.test.org/book/book_images/:data_file_path/:book_id/:style/:basename.:extension"
Hope this might be of help to somebody else :)
cheers
I'm using Thoughtbot's Paperclip gem to handle file uploads.
I'm finding that when I upload a file with spaces in the filename, it gets stored with the spaces replaced with underscores.
That's good.
I also tried uploading a file with special characters like ~ and so on and they all got replaced with underscores.
Great. Exactly what I want.
But why is it happening?
All I'm doing in my model is...
has_attached_file(
file_somefile,
:path => ":rails_root/public/system/other/path/elements/:basename.:extension"
)
Is this Paperclip's default behavior?
To add a little more information, this happens in Paperclip::Attachment#cleanup_filename in which the default restricted_characters /[&$+,/:;=?#<>[]{}\|\\^~%# ]/ are replaced with underscores.
It's not documented, but you can specify the :restricted_characters option to paperclip to change what gets replaced, e.g.
class User < ActiveRecord::Base
attr_accessible :avatar
has_attached_file :avatar, :restricted_characters => /#/ # only replaces '#'
end
OK, after a little more searching, I found this blog post that says, down at the bottom, that Paperclip actually does some minimal processing of filenames.
I'm using paperclip in a rails app and have the following three validations in my model
validates_attachment_presence :photo
validates_attachment_size :photo, :less_than=>1.megabyte
validates_attachment_content_type :photo, :content_type=>['image/jpeg', 'image/png', 'image/gif']
If the user forgets to add an attachment, all three validations fail and thus, the user is presented with the following three errors:
# Photo file name must be set.
# Photo file size file size must be between 0 and 1048576 bytes.
# Photo content type is not included in the list
I think it would be best to just show the first error in this instance since the other two errors are purely consequential... I would prefer the user to only ever see the second two errors if an attachment has been added but doesn't meet the validation criteria.
I'm certain there is no pre-baked validation that does this sort of thing and from reading the code in vendor/plugins/paperclip/lib/paperclip.rb I see that the validates_attachment_size method supports the :unless parameter as shown:
def validates_attachment_presence name, options = {}
message = options[:message] || "must be set."
validates_presence_of :"#{name}_file_name",
:message => message,
:if => options[:if],
:unless => options[:unless]
end
So, I was thinking that I could do something like the following:
validates_attachment_size :photo, :less_than=>1.megabyte, :unless=> :photo.blank
But that breaks the app. Anyone have any experience of doing this sort of thing? Would be a nice contribution to the paperclip source code.
EDIT:
I've tried using this:
validates_attachment_size :photo, :less_than=>1.megabyte,
:unless=> Proc.new { |image| image[:photo].nil? }
It doesn't quite work though as I've just managed to upload a 5mb mp3 with this validation in place. But it's promising as the error message doesn't appear when the user has not attached a photo.
validates_attachment_size :photo, :less_than => 1.megabyte,
:unless => Proc.new { |imports| imports.photo_file_name.blank? }
I think you can do it other way. Don't mess with validations. You probably have something like this in your form:
<%= f.error_messages %>
You can remove it and write your own helper to display error messages. Errors are stored in hash:
#photo.errors
Or if you want to get to them through form builder:
f.object.errors