How to upload image using paperclip without model in Rails 3? - ruby-on-rails

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 ?

Related

Attachments to non-persisting record in Rails

So I have a items/new.html.erb page that has a form for a new Items record.
Now the page has an image uploads section also, beside the new record form, where the user can upload multiple images. This UI design suggests that the user should be able to upload images, or attach images to the to-be-created record.
My current setup is when the user uploads an image in the page(this is handled via AJAX/rails UJS), the id of the uploaded image/images will be added in a hidden field in the new Item form. Then only when the main form is submitted will the images be attached to the newly created Item resource. I feel that this is an unusual way of handling this issue and that there is a more easy, clear, Rails way for this.
I call the images like this:
item.images
The page also allows that the user be able to sort or update the order of the Image attachments, but this I think is a topic that should be in another discussion.
How do you handle this, the first issue, properly and clearly in Rails?
Nested attributes
Rails has a built in mechanism called accepts_nested_attributes. Which lets you create nested records in the same request:
class Item
has_many :images
accepts_nested_attributes_for :images
end
class Image
belongs_to :item
has_one_attached :file
end
This will let you create an item and images with:
Item.create(name: 'Foo', image_attributes: [{ file: 'foo.jpg'}, { file: 'bar.jpg'}])
ActiveRecord will handle inserting the records in the correct order.
This allows you to have a non-nullable foreign key (item_id) and avoid orphaned records which is a very real problem with your solution. Referential integrity should be pretty high on your list of priorities.
This is used in the model together with fields_for in the view (the form).
<%= form_with(model: #item) do |form| %>
<%= form.fields_for(:images) do |image_fields| %>
<%= image_fields.file_field :file %>
<% end %>
<% end %>
And by passing an array of keys in the strong parameters:
params.require(:item).permit(:name, image_attributes: [:file])
ActiveStorage's has_many_attached
ActiveStorage also lets you setup a one to many assocation without a model by using has_many_attached. The attachements are stored in the active_storage_attachments table. However there is no way as far as I know of attaching additional metadata (such as the ordering) to the attachements.

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.

Saving Images using Paperclip

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.

Is it possible to update more than one database table with one form submission in ruby on rails?

Let's say:
[ Micropost ] -> has_one -> [ MicropostPhotoAlbum ] -> has_many -> [ MicropostPhotos ]
If Micropost had one photo it wouldn't need a MicropostPhotoAlbum and I could just add an "image" column to my microposts table and work smoothly with carrierwave.
My form below would work fine:
= form_for #micropost, :remote => true do |f|
= f.file_field :image # Needed for image previewing with html5 file api
= f.hidden_field :user_id
= f.text_area :content
= f.submit "Post"
All I'd need to do is mount an upload to my micropost model and I'd be set. The image path would upload directly to the microposts table image column e.g. photo.png.
Well as you can see above each micropost won't have any photos but instead have one album that contains many photos. Now my form won't work seeing as there will be a micropost_album_id column instead of an image column.
How can I use my current form to upload a photos to the photos table and post my micropost content in one submit? Is there any simple way around this other than reverting back to making each micropost have one photo?
Kind regards
This looks like a job for nested attributes.
Here is an (old, admittedly) article on nested attributes in forms. fields_for is the key.

Ruby on Rails and Paperclip

I have a polymorphic Attachment model to save images uploaded by users. Users can set any of their own as a profile pic.
To this, I created an "avatar_id" column in the User database to basically save the attachment id to create the reference. I also added an avatar action to the User model:
def avatar
self.attachments.first(:conditions => ['id = ?', self.avatar_id])
end
The problem is that if I try to make this work
<%= #user.avatar.url %>
It doesn't work because the url method doesn't exist. I need to specify that is an paperclip object but I don't get where and how I should do it. I'm probably missing something obviously here.
Your Attachment model should have a set of attachment fields: maybe attachment_file_name, attachment_content_size, etc.
So when you reference #user.avatar, you're really just referencing the entire Attachment record rather than the paperclip-specific columns.
Try this, substituting "attachment" for whatever you called your paperclip columns:
<%= #user.avatar.attachment.url %>

Resources