I have a project model where i can create projects and to each project upload videos and photos. I'm using nested attributes. My form displays 5 photo upload buttons and 5 video upload buttons. I want to hide the buttons that are used. For example: If I've uploaded 1 photo and 2 videos I want my edit form to display 4 upload photo buttons and 3 for the videos.
Right now, if a photo is uploaded it hides 1 upload button from the photos and one from the videos. Does anyone know how to make this possible?
Here is my controller.
def new
#project = Project.new()
(5 - #project.assets.length).times { #project.assets.build }
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #project }
end
end
# GET /projects/1/edit
def edit
#project = Project.find_by_permalink(params[:id])
(5 - #project.assets.length).times { #project.assets.build }
end
Gems:
gem "paperclip", "~> 3.5"
# handels video upload
gem "paperclip-ffmpeg", "~> 1.0.0"
Project Model:
class Project < ActiveRecord::Base
has_permalink :title
default_scope :order => 'created_at desc'
attr_accessible :title, :description, :assets_attributes, :dependent => :destroy
validates_uniqueness_of :title
validates_presence_of :title
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
end
Asset Model:
class Asset < ActiveRecord::Base
require 'paperclip'
require 'paperclip-ffmpeg'
belongs_to :project, :foreign_key => "project_id"
attr_accessible :project_id, :photo, :video
has_attached_file :photo, :styles => { :thumb => "130x130#", :medium => "300x300#", :small => "160x160#"}
has_attached_file :video, :styles => {
:mobile => {:geometry => "400x300", :format => 'flv', :streaming => true}
}, :processors => [:ffmpeg, :qtfaststart]
end
You need to differentiate the video-assets and image-assets. That will do.
Also, if you can share with us what gems are being used, we could help better.
Solved it by making a "add" button, to add a file field on request.(Did one for the video upload and one for the photo upload.)
<div class="row">
<div class="newPaperclipFiles col-md-4 col-md-offset-1" style="overflow: hidden;">
<h3 style="color:rgb(31,154,207);">Upload a Photo</h3>
<hr style="margin-left: -20%; width: 280px !important;"></hr>
<%= f.fields_for :assets do |asset_photo| %>
<% if asset_photo.object.new_record? %>
<div class="btn custumbtn btn-xs" id="duplp" onlick="duplicatep()">Add</div>
<div id="duplicaterp">
<%= asset_photo.file_field :photo %>
</div>
<% end %>
<% end %>
</div>
</div>
js:
<script type="text/javascript">
document.getElementById('duplp').onclick = duplicatep;
var i = 0;
var original = document.getElementById('duplicaterp');
function duplicatep() {
var clone = original.cloneNode(true);
clone.id = "duplicaterp" + ++i;
original.parentNode.appendChild(clone);
}
</script>
Related
Hey i have a rails app that i am uploading images with paperclip....
So i have a comic_review scaffold that i upload images of comic covers and i also have a news scaffold where i post news and images.....
When i edit news/1/edit and upload a picture the comics_review/1 picture becomes the same as the news one and vice a versa.
I checked the links in the views to make sure that i is correct and they seem to be ok...
heres my view
home.html.erb
<h2 style="color: black; font-size: 30px;"><%= #comic_review1.title %></h2>
<p><%= #comic_review1.content %></p>
<%= link_to 'Read More...', comic_review_path(#comic_review1) %>
<%= image_tag #comic_review1.photo, class: "homepage_comics" %>
news/show.html
<%= #news.author %>
<%= #news.date %>
<%= image_tag #news.photo, class: 'pull-left', style: 'margin-right: 10px;' %>
heres my controller
static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
#user = current_user
#article = Article.first
#comic_review1 = ComicReview.find(1)
#comic_review2 = ComicReview.find(2)
#comic_review3 = ComicReview.find(3)
#comic_review4 = ComicReview.find(4)
end
def comics
#comic_review1 = ComicReview.find(1)
#comic_review2 = ComicReview.find(2)
#comic_review3 = ComicReview.find(3)
#comic_review4 = ComicReview.find(4)
end
def batnews
#article = Article.first
#news_all = News.all
end
end
heres my model
comic_review.rb
class ComicReview < ActiveRecord::Base
attr_accessible :content, :credits, :review, :title, :photo, :comicreview
has_attached_file :photo, :styles => { :small => '400x400' },
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => ":attachment/activities/:id/:style.:extension",
:bucket => 'goddam_batman_pics'
has_many :comments, as: :commentable, dependent: :destroy
end
news.rb
class News < ActiveRecord::Base
attr_accessible :title, :author, :date, :content, :photo
has_attached_file :photo, :styles => { :small => '400x400' },
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => ":attachment/activities/:id/:style.:extension",
:bucket => 'goddam_batman_pics'
end
controllers are your basic controllers that gets generated by the scaffold
so whenever i update a photo for news/1 the photo for comic_reviews/1 gets the same photo as the news one
any help would be appreciated thank you
I'm pretty sure the problem is that you're giving the "photo" the same name in both models. Try naming one comic_photo and the other news_photo, or alternately, explore Polymorphic Associations.
Dated Railscast link, but gives you the idea - http://railscasts.com/episodes/154-polymorphic-association
PS - Bonus points for figuring out how to load four ComicReviews in one query rather than four in those controllers.
ok so what i had to do was in my model i changed the path from
:path => ":attachment/activities/:id/:style.:extension",
to
:path => "/image/:id/:filename",
and it seems to be working
I want to make polymorphic associations with paperclip, and allow my user to have one avatar and multiple images.
Attachment model:
class Attachment < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
end
class Avatar < Attachment
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
class Image < Attachment
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
User Model:
has_one :avatar, :as => :attachable, :class_name => 'Attachment', :conditions => {:type => 'avatar'}
accepts_nested_attributes_for :avatar
User Controller:
def edit
#user.build_avatar
end
User View form:
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= f.fields_for :avatar do |asset| %>
<% if asset.object.new_record? %>
<%= asset.file_field :image %>
<% end %>
<% end %>
when I attempt to save the changes I get the error => unknown attribute: avatar
if I remove the :class_name => 'attachment' in the has_one association I get the error =>
uninitialized constant User::Avatar
I need to also attach avatars to blog posts, so I need the association to be polymorphic (or atleast i think so)
I am stumped and any help would be greatly appreciated.
I do have a project in the works that is successfully using Paperclip and polymorphic associations. Let me show you what I have, and maybe you can apply it to your project:
class Song < ActiveRecord::Base
...
has_one :artwork, :as => :artable, :dependent => :destroy
accepts_nested_attributes_for :artwork
...
end
class Album < ActiveRecord::Base
...
has_one :artwork, :as => :artable, :dependent => :destroy
accepts_nested_attributes_for :artwork
...
end
class Artwork < ActiveRecord::Base
belongs_to :artable, :polymorphic => true
attr_accessible :artwork_content_type, :artwork_file_name, :artwork_file_size, :artwork
# Paperclip
has_attached_file :artwork,
:styles => {
:small => "100",
:full => "400"
}
validates_attachment_content_type :artwork, :content_type => 'image/jpeg'
end
the songs form and the albums form include this as a partial:
<div class="field">
<%= f.fields_for :artwork do |artwork_fields| %>
<%= artwork_fields.label :artwork %><br />
<%= artwork_fields.file_field :artwork %>
<% end %>
don't forget to include :html => { :multipart => true } with the form
artworks_controller.rb
class ArtworksController < ApplicationController
def create
#artwork = Artwork.new(params[:artwork])
if #artwork.save
redirect_to #artwork.artable, notice: 'Artwork was successfully created.'
else
redirect_to #artwork.artable, notice: 'An error ocurred.'
end
end
end
and finally, an excerpt from songs_controller.rb:
def new
#song = Song.new
#song.build_artwork
end
I'm not sure you really need to be polymorphic. How about this approach, which uses has_many :through? In plain English, the user has one avatar which has multiple images, and through this association you can call User.images to get the collection of images associated with the avatar.
http://guides.rubyonrails.org/association_basics.html
class User < ActiveRecord::Base
has_one :avatar
has_many :images, :through => :avatar
end
class Avatar < ActiveRecord::Base
belongs_to :user
has_many :images
end
class Image < ActiveRecord::Base
belongs_to :avatar
has_attached_file :image, :styles => { :thumb => "150x150>", :view => "260x180>" },
end
Having said all of this, I am left to wonder why you need to go through all this anyway. Why not just do
class User < ActiveRecord::Base
has_many :avatars
end
which would give you as many images (avatars) as you want.
Here's the structure of my code. I have a video attached with each cresponse and as far as I can tell I have been successful in uploading it. The problem comes when I need to convert it after the structure is saved. I wish to access the newly updated nested attribute (see lesson_controller) but am not sure how to go about doing so.
Many thanks!
Pier.
lesson.rb
class Lesson < ActiveRecord::Base
has_one :user
has_many :comments, :dependent => :destroy
has_many :cresponses, :dependent => :destroy
acts_as_commentable
accepts_nested_attributes_for :comments, :reject_if => lambda { |a| a[:body].blank? }, :allow_destroy => true
accepts_nested_attributes_for :cresponses
and here's cresponse.rb
class Cresponse < ActiveRecord::Base
belongs_to :lesson
attr_accessible :media, :accepted, :description, :user_id
# NOTE: Comments belong to a user
belongs_to :user, :polymorphic => true
# Paperclip
require 'paperclip'
has_attached_file :media,
:url => "/system/:lesson_id/:class/:basename.:extension",
:path => ":rails_root/public/system/:lesson_id/:class/:basename.:extension"
Here's my HTML view
<% #cresponse = #lesson.cresponses.build %>
<%= form_for #lesson, :html => { :multipart => true } do |f| %>
<td class="list_discussion" colspan="2">
<div class="field">
<%= f.fields_for :cresponses, #cresponse, :url => #cresponse, :html => { :multipart => true } do |builder| %>
Upload : <%= builder.file_field :media %><br />
Description : <%= builder.text_field :description %>
<%= builder.hidden_field :user_id , :value => current_user.id %>
<% end %>
</div>
</td>
and here's lesson_controller.rb - update
def update
#lesson = Lesson.find(params[:id])
respond_to do |format|
if #lesson.update_attributes(params[:lesson])
**if #lesson.cresponses.** <-- not sure how to find the cresponse that I need to convert
puts("Gotta convert this")
end
Think I should answer my own question ..
Basically for lesson_controller.rb
params[:lesson][:cresponses_attributes].values.each do |cr|
#cresponse_user_id = cr[:user_id]
#cresponse_description = cr[:description]
if cr[:media]
.... and so on
I'm trying to delete each single image uploaded for a model (work has many images) but now my code works like this: I have three images uploaded in a work, I want to delete just one but when I check the image's checkbox and submit the update action it will delete all the three images.
Here is my work model's code:
before_save :destroy_image?
belongs_to :category
has_many :images, :as => :assetable, :class_name => "Work::Image", :dependent => :destroy
accepts_nested_attributes_for :images, :reject_if => proc { |attributes| attributes['attachment'].blank? }
def image_delete
#image_delete ||= "0"
end
def image_delete=(value)
#image_delete = value
end
private
def destroy_image?
self.images.clear if #image_delete == "1"
end
end
class Work::Image < Asset
has_attached_file :attachment, :styles => {:small => "200x150>", :large => "400x300>"},
:url => "/uploads/works/:id/:style/:basename.:extension",
:path => ":rails_root/public/uploads/works/:id/:style/:basename.:extension"
end
I think the problem is that delete all images
self.images.clear if #image_delete == "1"
but I don't understand how to fix it. I hope in your help.
You should use the :allow_destroy options of accepts_nested_attributes_for instead.
And in your form something like this:
<% #work.images.each do |image| %>
<%= f.fields_for :images, image do |image_fields| %>
<%= image_tag image.url(:small) %>
<%= image_fields.check_box :_destroy %>
<% end %>
<% end %>
I am reading this tutorial : http://sleekd.com/general/adding-multiple-images-to-a-rails-model-with-paperclip/
because i need Save the product images in a independent model. However when Product.create execute don´t save the data for product images model.
NOTE: I use the new pack action because i need to use ajax for create a new product.
Please I need Help.
My Code
Controllers
class Admin::PacksController < ApplicationController
def new
#pack = Pack.new
#product = Product.new
4.times {#product.product_images.build} # added this
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #pack }
end
end
def create_starred_product
product = Product.new(params[:product])
product.save
...
end
View
<% form_remote_for #product, :url => {:controller => "products", :action => "create_starred_product"}, :html => {:multipart => true} do |f| %>
<div id="content">
....#OTHER FIELDS OF PRODUCT. ITS SAVE METHOD IS OK
<div id="images-selector">
<span class="fleft">Imágenes</span><br/>
<% count = 0 %>
<% f.fields_for :product_images do |builder| %>
<% if builder.object.new_record? %>
<label>
Imagen <%= "#{count = count + 1}" %>
</label>
<%= builder.file_field :photo, :class => "textarea" -%><br/>
<% end %>
<% end %>
</div>
<p><%= f.submit "Crear" %></p>
</div>
<% end %>
Models
class Product < ActiveRecord::Base
has_many :packs, :through => :pack_products
has_many :product_images, :dependent => :destroy
#PAPERCLIP
accepts_nested_attributes_for :product_images, :reject_if => lambda { |t| t['product_image'].blank? }
end
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_file :photo, :url => "/:attachment/:class/:id/:style_:basename.:extension", :styles => { :medium => "300x300>", :thumb => "100x100>", :small => "30x30>" }
end
You can't upload files using AJAX, just like you said. There are, however, alternate solutions.
The common technique to accomplish this is the usage of an iframe. Have a look here, this tutorial is oriented towards attachment_fu but it'll work with paperclip as well. Uploadify is worth checking out and can also be used with paperclip on rails 2.3 and rails 3.
I found the solution together with my partner.
My error was in nested attributes form, no in Ajax.so I found the solution for to use paperclip with Ajax. Now I posted example code.
However I explain the code.
Models
Two models
Product and Product_images
I wanted that when i created a product in ajax form (each product belongs_to pack).
Each product has many images in product_images model. Therefore I wanted save images too.
The code
Controller Ajax action
class ProductsController < ApplicationController
def create_starred_product
product = Product.new(params[:product])
product.save
render :update do |page|
page.replace_html 'star-product', :partial => "admin/products/star_product_name", :locals => {:star_product => product}
page.call "$j.modal.close"
end
end
end
Models
Products model
class Product < ActiveRecord::Base
has_many :packs, :through => :pack_products
has_many :product_images, :dependent => :destroy
#PAPERCLIP
accepts_nested_attributes_for :product_images#, :reject_if => lambda { |t| t['product_image'].blank? }
has_attached_file :photo, :url => "/:attachment/:class/:id/:style_:basename.:extension", :styles => { :medium => "300x300>", :thumb => "100x100>", :small => "30x30>" }
Product_images model
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_file :photo, :url => "/:attachment/:class/:id/:style_:basename.:extension", :styles => { :medium => "300x300>", :thumb => "100x100>", :small => "30x30>" }
end
end
View popup in ajax (These is a partial)
<script type="text/javascript">
$j(document).ready(function() {
$j('#product_submit').click(function(event) {
event.preventDefault();
$j('#uploadForm').ajaxSubmit({
beforeSubmit: function(a, f, o) {
o.dataType = 'json';
},
complete: function(XMLHttpRequest, textStatus) {
// XMLHttpRequest.responseText will contain the URL of the uploaded image.
// Put it in an image element you create, or do with it what you will.
// For example, if you have an image elemtn with id "my_image", then
// $('#my_image').attr('src', XMLHttpRequest.responseText);
// Will set that image tag to display the uploaded image.
}
});
});
});
</script>
<div id="new-starred-product" class="popup clearfix">
<div id="header">Nuevo producto estrella</div>
<% remote_form_for #product, :url => {:controller => "products", :action => "create_starred_product"}, :html => {:method => :post, :id => 'uploadForm', :multipart => true} do |f| %>
<div id="content">
<label>Nombre:</label> <%= f.text_field :name, :class => "textarea" %>
<br/>
<label>Precio:</label> <%= f.text_field :price, :class => "textarea" %>
<br/>
<%#= f.file_field :photo %>
<div id="images-selector">
<% count = 0 %>
<%# f.fields_for "product_images_attributes[]", ProductImage.new do |builder| %>
<% f.fields_for :product_images, 4.times {ProductImage.new} do |builder| %>
<% if builder.object.new_record? %>
<label>
Imagen <%= "#{count = count + 1}" %>
</label>
<%= builder.file_field :photo, :class => "file-upload" -%><br />
<br/>
<% end %>
<%#= builder.text_field :testfield %>
<!--ACA VA EL CODIGO PARA IMAGENES-->
<% end %>
</div>
<br/>
<label>Descripción</label><%= f.text_area :description, :rows => 10, :class => "textarea clearfix" -%>
<br/>
<p>
<%#= f.submit "Crear" %>
<%= link_to "Crear", "#", :id => "product_submit" %>
</p>
</div>
<% end %>
</div>
I am using jquery and jquery-form plugin (search in google)
You'll find two versions of ajax upload on https://github.com/apneadiving/Pic-upload---Crop-in-Ajax.
Branch master: it uses http://aquantum-demo.appspot.com/file-upload
Branch uploadify: It uses Uploadify: http://www.uploadify.com/
Both have built-in Crop.
The problem Was nested attributes form.later I posted the code
Another gem to help with this issue I've just found when I've had the same problem is remotipart - Highly recommended.