Using Rails 2, I try to separate different, dynamic image sizes trough another Model from the Paperclip-Model. My current approach, using a Proc, looks the following:
class File < ActiveRecord::Base
has_many :sizes, :class_name => "FileSize"
has_attached_file(
:attachment,
:styles => Proc.new { |instance| instance.attachment_sizes }
)
def attachment_sizes
sizes = { :thumb => ["100x100"] }
self.sizes.each do |size|
sizes[:"#{size.id}"] = ["#{size.width}x#{size.height}"]
end
sizes
end
end
class FileSize < ActiveRecord::Base
belongs_to :file
after_create :reprocess
after_destroy :reprocess
private
def reprocess
self.file.attachment.reprocess!
end
end
Everything seems to work out fine but apparently no styles are processed and no image is being created.
Did anyone manage doing stuff like this?
-- Update --
Obviously the method attachment_sizes on instance sometimes is not defined for # - but shouldn't instance actually be #?
For me this looks like altering instance..
The solution is simple. instance in my first example Proc is an instance of Paperclip::Attachment. As I want to call a File method, one has to get the calling instance inside the Proc:
Proc.new { |clip| clip.instance.attachment_sizes }
instance represents File-instance in the given example.
I'm assuming you have everything working with paperclip, such that you have uploaded an image and now the proc is just not working.
It should work. Try not putting the size in an array.
You are doing this
sizes = { :thumb => ["100x100"] }
But I have it where I'm not putting the size in an arry
sizes = { :thumb => "100x100" }
Give that a try :)
Related
I'm currently building an app which has a model Post. I'm using the paperclip gem to upload images, and everything is going well.
class Post < ActiveRecord::Base
has_attached_file :headerimage, styles: {banner => "400x300#"}
end
As you can see by my class above, if I were to get a Post object, I could get the banner image with the following in my view:
image = Post.first.headerimage(:banner)
Alias
However, in my app, it must have the image attribute image refer to the thumbnail image. So, in my models class, I wrote
class Post < ActiveRecord::Base
has_attached_file :headerimage, styles: {banner => "400x300#"}
alias_attribute :image, :headerimage
end
which allows me to get an image by calling the following:
image = Post.first.image
This is what I want - however, it gets the original image from paperclip, so it is equivalent to writing the following:
image = Post.first.headerimage instead of image = Post.first.headerimage(:banner)
How can I set up a proper alias_attribute to access the paperclip thumnail? I can't seem to find an answer anywhere else, and I am unsure how paperclip is actually working.
I thought I might logically be able to do something like
alias_attribute :image, :headerimage(:banner)
but that does not work.
You can just try this - basically call the original with arguments since aliases won't take parameter but we know the fixed parameter to pass:
alias :image, :headerimage
def headerimage(name=nil)
headerimage(name || :thumb)
end
I have the following ToyPhoto model:
require "open-uri"
class ToyPhoto < ActiveRecord::Base
belongs_to :toy
has_attached_file :image, :styles => {
:thumb => ["210x210>", :jpg]
}
def image_url=(value)
self.image = open(value)
end
end
When I upload a photo, I don't see the corresponding thumb folder being created. This is how I create the ToyPhoto objects:
params[:photos].each do |photo|
#toy_photo = ToyPhoto.new
#toy_photo.image_url = photo[:url]
#toy_photo.save
#toy.photos << #toy_photo
end
I do see photo being successfully uploaded to original folder, but no thumb folder created. Did I miss some configuration problem? I am suspecting that strong_parameter didn't defined when uploading from url, however I am not sure how to set strong_parameter in this case.
Thanks!
I believe that the problem in your code is how you specify the format of the thumb style. Reading the Paperclip API showed that the proper way to do this is like so:
has_attached_file :image, :styles => { :thumb => ["210x210#", :jpg] }
I'm writing my first RoR app and currently I'm working on allowing users to upload images. I'm using Paperclip for this purpose. One of the steps involves adding has_attached_file to my model:
class MyModel < ActiveRecord::Base
#...
has_attached_file :picture, styles: {
large: "120x150#>",
small: "60x75#>"
}
#...
end
If I do it like this, everything works smoothly (or so it seems). But I will also need to access the same constant values as integers somewhere else, so I've added a hash:
class MyModel < ActiveRecord::Base
#...
has_attached_file :picture, styles: {
large: "120x150#>",
small: "60x75#>"
}
def picture_sizes
{
large: {width: 120, height: 150},
small: {width: 60, height: 75}
}
end
#...
end
This creates an ugly redundancy. So I thought about writing a method generating the first hash from the second one, like this
class MyModel < ActiveRecord::Base
#...
has_attached_file :picture, styles: picture_sizes_as_strings
def picture_sizes
{
large: {width: 120, height: 150},
small: {width: 60, height: 75}
}
end
def picture_sizes_as_strings
result = {}
picture_sizes.each do |label, size|
result[:label] = "#{size[:width]}x#{size[:height]}#>"
end
return result
end
#...
end
But this rises an error:
undefined local variable or method `picture_sizes_as_strings' for #<Class:0x007fdf504d3870>
What am I doing wrong?
The problem is that you're trying to use an instance method picture_sizes_as_strings in a declaration (has_attached_image) that's run on the class level. It's the difference between calling
MyModel.picture_sizes_as_strings
and
MyModel.first.picture_sizes_as_strings
In the first case we are referring to a class method (a method on the class MyModel itself) and in the second case we are referring to an instance method (a method on the individual my_model object.)
So first of all you have to change the methods to class methods by prefixing their names with self., so:
def self.picture_sizes
{
large: {width: 120, height: 150},
small: {width: 60, height: 75}
}
end
Now that doesn't completely fix your problem yet, because has_attached_image is processed when the model is first parsed by ruby. That means it will try to run has_attached_image before you define self.picture_sizes so it will still say undefined method.
You can fix this by putting self.picture_sizes before the has_attached_file declaration but that's quite ugly. You could also put the data in a constant but that has its own problems.
Honestly there's no really pretty way to fix this. If it were me I'd probably reverse the whole process, define the styles as normal and then use a method to convert the strings to integers, something like this:
class MyModel < ActiveRecord::Base
has_attached_file :picture, styles: {
large: "120x150#>",
small: "60x75#>"
}
def numeric_sizes style
# First find the requested style from Paperclip::Attachment
style = self.picture.styles.detect { |s| s.first == style.to_sym }
# You can consolidate the following into one line, I will split them for ease of reading
# First strip all superfluous characters, we just need the numerics and the 'x' to split them
sizes = style.geometry.gsub(/[^0-9x]/,'')
# Next split the two numbers across the 'x'
sizes = sizes.split('x')
# Finally convert them to actual integer numbers
sizes = sizes.map(&:to_i)
end
end
Then you can call MyModel.first.numeric_sizes(:medium) to find out the sizes for a specific style, returned as an array. Of course you could change them into a hash too or whatever format you need.
the has_attached_file is evaluated at Runtime. You've defined an instance method, but you aren't calling the method from an instance context.
Try:
def self.picture_sizes_as_strings
# code here
end
Make sure you define the other method with self. also
and then:
has_attached_file :picture, :styles => picture_sizes_as_strings
should work.
I have a user model that is generated using Devise. I am extending this model using paperclip to enable file upload and also the processing of a file using a custom paperclip processor.
My paperclip field is declared in the user model as follows. PaperClipStorage is a hash that I create with the paperclip variables. Also, the being stored on AWS S3.
has_attached_file :rb_resume, PaperclipStorageHash.merge(:style => { :contents => 'resume_contents'}, :processors => [:resume_builder])
validates_attachment_content_type :rb_resume, :if => lambda { |x| x.rb_resume? }, :content_type => ['application/pdf', 'application/x-pdf', 'application/msword', 'application/x-doc']
The validates_attachment_content_type check is being done to make sure that it only processes pdf and MS word files.
My processor looks as follows
module Paperclip
class ResumeBuilder < Processor
def initialize(file,options = {}, attachment = nil)
#file = file
#attachment = attachment
puts "Attachment is not null " if !attachment.nil?
end
def make
rb = MyModule::MyClass.new(#file.path) ### Do something with the file
section_layout = rb.parse_html
#attachment.instance_write(:whiny, section_layout)
#file
end
end
end
In my user model I also have an after_save callback that is supposed to take the section_layout generated in the processors make method. Code is as follows
after_save :save_sections
def save_sections
section_layout = rb_resume.instance_read(:whiny)
# Do something with section_layout...
end
Now my problem is that the processor code is never being called, and I can't figure out why.
Because of that the section_layout variable is always nil.
Another point to note is that the same model also has two other has_attached_file attributes. None of the other two use a custom processor.
I've been struggling with this for last 3 hours. Any help would be greatly appreciate.
Thanks
Paul
Error in my has_attached_file declaration
has_attached_file :rb_resume, PaperclipStorageHash.merge(:style => { :contents => 'resume_contents'}, :processors => [:resume_builder])
should actually be
has_attached_file :rb_resume, PaperclipStorageHash.merge(:styles => { :contents => 'resume_contents'}, :processors => [:resume_builder])
Notice the plural styles as opposed to singular style
Is there anyway to have the validates_attachment_size except a dynamic file size limit? Here's an example:
class Document < ActiveRecord::Base
belongs_to :folder
has_attached_file :document
validates_attachment_size :document, :less_than => get_current_file_size_limit
private
def get_current_file_size_limit
10.megabytes # This will dynamically change
end
end
I've tried this but I keep getting an error saying "unknown method". Lambdas and Procs don't work either. Has anyone ever tried this? Thanks
Paperclip doesn't allow to pass function as size limit parameter. So you probably need to write custom validation:
validate :validate_image_size
def validate_image_size
if document.file? && document.size > get_current_file_size_limit
errors.add_to_base(" ... Your error message")
end
end
Long shot...
validates_attachment_size :document, :less_than => :get_current_file_size_limit
Usually when passing a function you have to pass the symbol and not the actual function.
There is a built-in Paperclip validation now:
validates_attachment_size :mp3, :less_than => 10.megabytes
Change mp3 to whatever your paperclipped file's name is.
See this post for more helpful Paperclip tips: http://thewebfellas.com/blog/2008/11/2/goodbye-attachment_fu-hello-paperclip