Saving Images using Paperclip - ruby-on-rails

I am just looking for some clarification with using paperclip for saving images. I am grabbing all my images stored in Flickr using the Flickraw Gem. I am grabbing the url for the image and saving that to my model,
Model
class Portfolio < ActiveRecord::Base
attr_accessible :taken, :title, :url, :url_large
end
then rendering using the image_tag helper..
Like so
<%= #portfolio.each do |p| %>
<%= image_tag(p.url_large, :size => "480x480") %>
<%= p.title %>
<% end %>
So this shows all my photos at 480 x 480.. However I understand that paperclip handles images better?
So i can install paperclip, add :avatar column to my Portfolio model (though ill prob call it photo) and its the next part i want to clarify.
Do i save the url to the image within the :avatar column and then use the paperclip helpers as normal? Im used to uploading physical images to my model using paperclip which generates a file name within that column (well thats from what I can see)
I save the attributes like so at the moment
flickr.photos.search(:user_id => FLICKR_USER_ID).each do |p|
info = flickr.photos.getInfo(:photo_id => p.id)
title = info.title
taken = info.dates.taken
square_url = FlickRaw.url_s(info)
original_url = FlickRaw.url_o(info)
Portfolio.where(title: title, url: square_url, taken: taken, url_large: original_url).first_or_create!
end
So where to save FlickRaw.url_o ?
Can anyone advise if im thinking about this correctly or do i have some things wrong?
Any help appreciated

You could check this other post save image from url by paperclip they explain how to insert a picture from an url.
But actually I think this will try to upload the image.

Related

Is there a way to have multiple file uploads turn into multiple models

So I have a model called Photo and obviously I don't want to upload one photo at a time, so I replaced the new photo form with multi-file uploading. I am not quite sure how I can make these file uploads turn into unique photo models.
<%= bootstrap_form_with(:model => photo, :local => true) do |form| %>
<%= form.file_field :image, :multiple => true, :direct_upload => true %>
<%= form.submit %>
<% end %>
Edit: I am using Active Storage on Rails 6.0.0 rc2
You can't make multiple photo models. You probally mean multiple records. A model is a blueprint of the table in your database.
Check your terminal logs when you submit the form and you will probally see that in the params you will have something like: photo => [ files here ]
So in your controller create you have to loop through the array and create a photo record for each photo, something like this:
def create
params[:photo].each do |photo|
Photo.create(file: photo.file)
end
For those that come across this problem, here was my solution:
def create
photo_params[:images].each do |image|
#photo = current_user.photos.build
#photo.image = image
#photo.save
end
end

Trying to render an image, but #<ActiveRecord::Associations::CollectionProxy []> is returned

my guides can have many guide_pics. In my show guide view, I want to show the pics. I'm trying to use
<%= image_tag #guide.guide_pics if #guide.guide_pics %>
Instead of the image, the page renders with the text:
So it seems like something is there, I just have to get the picture.
But in the debugger this gives
#<ActiveRecord::Associations::CollectionProxy []>
Does that mean an empty object is returned? If that is the case, maybe I seeded the db wrong:
g1.guide_pics.build(picture: File.open(File.join(Rails.root, '/public/2015-08-28 18.55.47.jpg')))
Otherwise, maybe I set up the association wrong.
My guide_pic model
class GuidePic < ActiveRecord::Base
belongs_to :guide
validates :guide_id, presence: true
validates :picture, presence: true
default_scope -> { order(created_at: :desc) }
end
My guide model
class Guide < ActiveRecord::Base
belongs_to :user
has_many :guide_pics, dependent: :destroy
#mount_uploader :picture, PictureUploader
end
guide_pics is an association, and will return one or more guide_pics.
So you will have to iterate over all guide_pics, as follows:
<% #guide.guide_pics.each do |guide_pic| %>
<%= image_tag guide_pic.picture.url %>
<% end %>
Notice I write guide_pic.picture.url: I am assuming you are using a gem for your attachments, like carrierwave or something similar, which can build a url for your image --if not, you will do add that yourself.
But if you just want to show the first picture, you could do something like
<%= image_tag #guide.guide_pics.first.picture.url if #guide.guide_pics.count > 0 %>
Rails is doing correctly, you are misunderstanding.
while a model is having many pictures (has_many relation) rails is auto-generating a method to access those.
In this case Guide.guide_pics is making a query to the DB, something like
SELECT * from guide_pics where guide_id=5
as you can see - this is selecting all rows, the hole set of data which is associated with one guide. This is what ActiveRecord is called an ActiveRecord::Collection.
First of all, yes, you seeded the DB wrong!. The .build method is not saving anything to the database, you should call the .create method.
If you are having any objects in your database you have 2 (3) ways of rendering the image.
<%= image_tag #guide.guide_pics.first.url if #guide.guide_pics.any? %>
This will take the first picture from the Collection if any is in there.
This is bad code.
another option would be to say .take instead of .first.
better code would be something like
<%= image_tag #guide.preview_picture %>
to do so you need a model function
class Guide
def preview_picture
guide_pics.first.url || "/images/no-logo.jpg"
end
end
this will automatically takes the first picture or returns the string of a default one.
my advise to you: have a look on Carrierwave, Dragonfyl or Paperclip. Thise are awesome FileUploading Gems - fitting your needs.
Look at the documentation of image_tag it expects source of image not collection_proxy You need to iterate the list and show images one by one
<% #guide.guide_pics.each do |pic|%>
<%= image_tag pic %>
<% end %>
Note: pic can be url or name of pic depending on your pics saving technique.

How to upload image using paperclip without model in Rails 3?

I want to implement Papereclip in Rails 3.2 without a model.
I am very new to RoR and Paperclip.
I followed through THIS tutorial to use paperclip. It is running successfully.
But in this tutorial they have shown use of the model, I dont want to use the model or dont want to modify the existing model.
Rails is object oriented.
# Article model
attr_accessible :image
# Paperclip attachment code and whatever rules and conditions you want.
The image attribute is actually a column from your database and an attribute accessible from your Article model. That image attribute will need to be a string type (varchar) to store the url where the image is saved.
For example if your article has an image attribute, in your view file Article#Show you can display your image through the article object with the image attribute as <%= image_tag #article.image.url %>.
If you want to have many images in a same article then you will want to create 2 models (Article and Image) and have an association where
# Article model
has_many :images
accepts_nested_attributes_for :images
# Image model
attr_accessible :image_url
belongs_to :article
# paperclip attachments...
With this association you can then fetch and display your images by doing
<% #article.images.each do |image| %>
<%= image_tag image.image_url.url %>
<% end %>
Technically you don't need to store the url of your image in the database, you can store it in variable, but then it will only be valid during the session and will disappear afterwards. If you want to view your image at a later date, then yes you need to store it in a database.
For not using a seperate model you can check Paperclip Docs. What is basically done here is that the image is stored as an atrribute of an existing model.
About not using a model at all, how do you want to associate the image object to some existing record ? Wont that be required in your project ?

Direct Uploads to S3 using Carrierwave

I've recently converted the below from using Paperclip to Carrierwave uploading to Amazon S3 so I can make use of the carrierwave_direct gem and then Sidekiq or another background processing gem.
class Release < ActiveRecord::Base
has_many :releases_tracks, :dependent => :destroy
has_many :tracks, :through => :releases_tracks, :order => "releases_tracks.position DESC"
accepts_nested_attributes_for :tracks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => :true
accepts_nested_attributes_for :releases_tracks
end
class Track < ActiveRecord::Base
mount_uploader :track, TrackUploader
has_many :releases_tracks, :dependent => :destroy
has_many :releases, :through => :releases_tracks
end
/views/releases/track_upload.html.erb
<%= form_for(#release, :html => { :multipart => true }) do |f| %>
<h3>Upload Tracks for <%= #release.title %></h3>
<% index = 0 %>
<%= f.fields_for :tracks do |builder| %>
<%= #release.tracks[index].name %>
<%= f.file_field :track, :class => "file styled", :title => 'Select Track'%>
<% index += 1 %>
<% end %>
<%= f.submit "Upload Tracks", :class => "submit" %>
<% end %>
Carrierwave uploads are working, but I can't figure out how to get the direct part working. Partly because I can't figure out how to incorporate the suggested form code:
<%= direct_upload_form_for #uploader do |f| %>
<%= f.file_field :track %>
<%= f.submit %>
<% end %
Or the where in my track OR release controller I place the suggested:
#uploader = User.new.track
#uploader.success_action_redirect = new_user_url
The readme https://github.com/dwilkie/carrierwave_direct and Railscast http://railscasts.com/episodes/383-uploading-to-amazon-s3 both point towards uploading your file first and then creating your database entry. In my app the db entries already exist. The Railscast does say it's possible but doesn't go through it. So that's the first problem.
The second is that I need to upload more than one file at a time. The code above does achieve that, but very slowly and it of course renders my app pretty useless as it does so.
Can anyone help? Massive thanks in advance!
First of all I would advise you not to use carrierwave_direct, I really don't like this gem, for many reasons.
One of those reasons, is that as it's said in the docs
Please be aware that this gem only supports single
file uploads. If you want to upload multiple files simultaneously
you'll have to use a javascript or flash uploader.
But if you want to use it, here is what I guess you have to do :
So first about the
#uploader = User.new.track
#uploader.success_action_redirect = new_user_url
It seems you are trying to upload tracks, and as you said your models have already been created, I guess your are trying to upload new tracks for an existing release. Correct me if I'm wrong.
so you should create the #uploader var in the #track_upload method of your ReleasesController.
class ReleasesController
...
def track_update
#uploader = User.new.track
#uploader.success_action_redirect = new_user_url
end
...
end
then in the associated view (/views/releases/track_upload.html.erb), you can use the direct_upload_form
<%= direct_upload_form_for #uploader do |f| %>
<%= f.file_field :track %>
<%= f.submit %>
<% end %>
The form will upload the file directly to s3, just after you selected the file. Then I don't know exactly how, but carrierwave_direct should give you back the url of the uploaded file.
I'm not sure about that as I've never been that far with it, but the idea is that your file just got uploaded to s3, now it has to be linked to your model, so the file doesn't get 'lost'.
So maybe carrierwave_direct is doing things on its own (I doubt that ...) by doing some ajax requests or anything else.
Anyway as you want to upload more than one file, I'd like to point you to a tutorial I recently wrote
This shows how to upload files directly to s3, without carrierwave_direct, but by doing things on your own. This requires a little bit more code and time, but you have more control about what's happening.
In your case, you'll want to put the form I'm using in my tutorial in your view, in the /views/releases/track_upload.html.erb view.
Then once you'll select a file, the successful AJAX request(emitted by the jQueryFileUpload plugin) will give you the URL of the uploaded file so you can save it in your Track model (you'll probably want to emit a new AJAX request to your server to create the new Track model, or to populate an other form on the page, like the one you were using in the /views/releases/track_upload.html.erb file, and then the tracks will be saved on submit.)
I'm not sure I'm really clear about that, let me know if you need more explanations.
And the good thing about that is that if you simply add multiple to your file input, then the awesome jQueryFileUpload plugin will send a request per file to s3, then you'll get the URL's of the uploaded files in each ajax results :D
And you can tweak things to add progress bars, and things like that with the jQuery plugin, you can really create awesome things.
Hope it'll help you !

Problem with file uploads in a nested form using Rails3 with Mongoid and Carrierwave

Im having a problem transferring an SQLlite Rails 3 app over to a Mongoid Rails 3 app. In the SQLlite version, I am easily able to include an image upload form (using Paperclip) from one model ('image') within a nested form from another model ('product'). Here's my 'new' product form:
<%= form_for #product, :html => {:multipart => true} do |f| %>
<% f.fields_for :images do |image_form| %>
<%= f.label :productphoto %>
<%= f.file_field :productphoto %><br />
<% end %>
<% end %>
And here's the 'show' view:
<% #product.images.each do |image| %>
<%= image_tag image.productphoto.url(:gallerythumb) %><br />
<% end %>
When I try to use the same product views in my Mongoid Rails 3 app (using Carrierwave), I get the following error:
TypeError in Stores#show:
can't convert nil into String
<%= image_tag product.image.url(:gallerythumb) %>
Im pretty sure my models in the Mongoid version are correct because if I add a string (like 'name') to my 'image' model and nest that in the 'Product' form, it works. Also, Im able to upload an image into a non-nested model form.
Any help would be greatly appreciated!
I just had a similar problem myself. The problem is not the image upload I think, but the problem is that Rails doesn't recognize :images as being an Array. If you look into the Rails source of the fields_for helper you see that it checks for a method "_attributes=". If that's not there the form will be posted as normal fields and not as an array (params will be "images" instead of "images[0]")
You have to add the following line to your model:
accepts_nested_attributes_for :images
It is carrierwave or mongoid bug
https://github.com/jnicklas/carrierwave/issues#issue/81
This is most likely the issue that Lewy linked to -- that problem is specific to arrangements where your Carrierwave uploader is mounted on a child document in an embedded association and you are saving the parent, and though you don't explicitly show if this is how your data is modeled, I suspect that's the case since you noted that it works with a non-nested form (presumably saving the child document then, not the parent).
If you dig around in the discussions linked from that issue, you'll find some proposed workarounds. Here's what I ended up with to get Carrierwave working in this situation for me:
https://gist.github.com/759788
Full credit is to due to zerobearing2 whose gist I forked, I just made minor changes to get it working in Rails 3.0.3 and commented on my gist with summary info on the relevant discussions.

Resources