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.
Related
I have been developing a rails app that uploads and processes images. Images, along with other string information is submitted via a form_for. I've been researching this topic for about 16 hours now and no solution has worked. Honestly it's like rails isn't even reading my code.
One Processmodel has many Assets, where an Asset is just a model to hold one image file. When creating processmodels, I can never access the asset, always recieving the cannot mass-assign attirbutes: assets_attributes
Completed 500 Internal Server Error in 13ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: asset):
app/controllers/process_controller.rb:20:in `new'
app/controllers/process_controller.rb:20:in `create'
-
This form is used in new.html.erb
<%= semantic_form_for #processmodel, :url => { :action => 'create' }, :html => { :multipart => true } do |f| %>
<%= f.input :batch, :as => :string, :name => "Batch" %>
<%= f.input :batchset, :as => :string, :name => "Batchset" %>
<%= f.input :numSlots, :as => :number, :name => "Number of slots" %>
<%= f.input :key, :as => :file, :name => "Key" %>
<%= f.semantic_fields_for :asset do |asset| %>
<%= asset.input :asset, :as => :file, :label => "Image" %>
<% end %><br />
<%= f.submit %>
<% end %>
-
class Processmodel < ActiveRecord::Base
attr_accessible :user_id, :batch,
:batchset, :numSlots,
:key,:assets_attributes
attr_accessor :key_file_name
has_many :assets, :dependent => :destroy
belongs_to :user
has_attached_file :key
# :url => Rails.root.join('/assets/readimages/:basename.:extension'),
# :path => Rails.root.join('/assets/readimages/:basename.:extension'),
accepts_nested_attributes_for :assets, :allow_destroy => true
.
.
.
end
-
require 'RMagick'
class Asset < ActiveRecord::Base
attr_accessible :results_string,
:name,
:ambiguous_results,
:image
belongs_to :batch_element
belongs_to :processmodel
has_attached_file :image
validates_attachment_presence :image
end
-
class ProcessController < ApplicationController
def create
#Processmodel = Processmodel.new(params[:processmodel])
#Processmodel.save
all_img = Array.new(#processmodel.assets.all)
respond_to do |format|
if #processmodel.beginRead(...)
redirect_to :action => 'results_main', :controller => 'results'
else
format.html { render action: "new" }
end
end
end
-
def new
#processmodel = Processmodel.new
#5.times{#processmodel.assets.build}
respond_to do |format|
format.html #new.html.erb
end
end
Am requesting an ideas on how to fix this and get my app working.
You need to update your database migration. Run:
rails g migration AddIdToAsset processmodel_id:integer
rake db::migrate
You've called your attached file :image here:
has_attached_file :image
But you call it :asset in your view:
<%= asset.input :asset, :as => :file, :label => "Image" %>
To fix, just change this line to
<%= asset.input :image, :as => :file, :label => "Image" %>
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 have this structure models
class Tournament < ActiveRecord::Base
AGES = ["5u", "6u", "7u", "8u"]
has_many :courts, :dependent => :destroy
accepts_nested_attributes_for :courts, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
class Court < ActiveRecord::Base
belongs_to :tournament, :autosave => true
has_many :ages, :dependent => :destroy
accepts_nested_attributes_for :ages, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
class Age < ActiveRecord::Base
belongs_to :court
Now my forms look like this
_form.html.erb
<%= semantic_form_for #tournament do |f| %>
<%= f.inputs do %>
<%= f.input :name, :hint => "What is the name of the Tournament?" %>
<%= f.semantic_fields_for :courts do |builder| %>
<%= render :partial => "court_fields", :locals => { :f => builder } %>
<% end %>
_court_fields.html.erb
<div class="nested_fields">
<%= f.input :name, :input_html => {:class => "name"} %>
<%= f.semantic_fields_for :ages do |builder| %>
<%= render :partial => "age_fields", :locals => { :f => builder } %>
<% end %>
_age_fields.html.erb
Testing ...am I getting in here
<%= f.input :name, :as => :check_boxes, :collection => Tournament::AGES, :input_html => {:class => "age_limits"} %>
everything seems to work well except nothing shows up in the ages_fields partial...not the checkboxes and not even the dummy text Testing ...am I getting in here is not displaying....any ideas what could be causing the issue
The obvious reason I can think of: are you sure your Court has ages ?
[EDIT] That the Court has the relation was indeed clear to me.
But your code will only show an age for a court if it already exists.
From your output in the comments: the court has no actual ages so no ages are shown.
If you do this in your controller:
def new
#tournament = Tournament.new
#tournament.courts.build
#tournament.courts[0].ages.build
end
This will make sure that you have at least one (empty) court and one (empty) age.
Otherwise you could also consider using a gem like cocoon to dynamically add new elements if needed.
Hope this helps.
I can't seem to find an example that is complete in all the components. I am having a hard time deleting image attachments
Classes
class Product
has_many :product_images, :dependent => :destroy
accepts_nested_attributes_for :product_images
end
class ProductImage
belongs_to :product
has_attached_file :image #(etc)
end
View
<%= semantic_form_for [:admin, #product], :html => {:multipart => true} do |f| %>
<%= f.inputs "Images" do %>
<%= f.semantic_fields_for :product_images do |product_image| %>
<% unless product_image.object.new_record? %>
<%= product_image.input :_destroy, :as => :boolean,
:label => image_tag(product_image.object.image.url(:thumb)) %>
<% else %>
<%= product_image.input :image, :as => :file, :name => "Add Image" %>
<% end %>
<% end %>
<% end %>
<% end %>
Controller
class Admin::ProductsController < AdminsController
def edit
#product = Product.find_by_permalink(params[:id])
3.times {#product.product_images.build} # added this to create add slots
end
def update
#product = Product.find_by_permalink(params[:id])
if #product.update_attributes(params[:product])
flash[:notice] = "Successfully updated product."
redirect_to [:admin, #product]
else
flash[:error] = #product.errors.full_messages
render :action => 'edit'
end
end
end
Looks good, but, literally nothing happens when I check the checkbox.
In the request I see:
"product"=>{"manufacturer_id"=>"2", "size"=>"", "cost"=>"5995.0",
"product_images_attributes"=>{"0"=>{"id"=>"2", "_destroy"=>"1"}}
But nothing gets updated and the product image is not saved.
Am I missing something fundamental about how 'accepts_nested_attributes_for' works?
From the API docs for ActiveRecord::NestedAttributes::ClassMethods
:allow_destroy
If true, destroys any members from the attributes hash with a _destroy key and a value that evaluates to true (eg. 1, ‘1’, true, or ‘true’). This option is off by default.
So:
accepts_nested_attributes_for :product_images, allow_destroy: true
I have just installed paperclip into my ruby on rails blog application. Everything is working great...too great. I am trying to figure out how to tell paperclip not to output anything if there is no record in the table so that I don't have broken image links everywhere. How, and where, do I do this?
Here is my code:
class Post < ActiveRecord::Base
has_attached_file :photo, :styles => { :small => "150x150"}
validates_presence_of :body, :title
has_many :comments, :dependent => :destroy
has_many :tags, :dependent => :destroy
has_many :ugtags, :dependent => :destroy
has_many :votes, :dependent => :destroy
belongs_to :user
after_create :self_vote
def self_vote
# I am assuming you have a user_id field in `posts` and `votes` table.
self.votes.create(:user => self.user)
end
cattr_reader :per_page
##per_page = 10
end
View
<% div_for post do %>
<div id="post-wrapper">
<div id="post-photo">
<%= image_tag post.photo.url(:small) %>
</div>
<h2><%= link_to_unless_current h(post.title), post %></h2>
<div class="light-color">
<i>Posted <%= time_ago_in_words(post.created_at) %></i> ago
</div>
<%= simple_format truncate(post.body, :length => 600) %>
<div id="post-options">
<%= link_to "Read More >>", post %> |
<%= link_to "Comments (#{post.comments.count})", post %> |
<%= link_to "Strings (#{post.tags.count})", post %> |
<%= link_to "Contributions (#{post.ugtags.count})", post %> |
<%= link_to "Likes (#{post.votes.count})", post %>
</div>
</div>
<% end %>
To see, if there is a file associated with post, you can use post.photo.file?
<%= image_tag post.photo.url(:small) if post.photo.file? %>
has_attached_file takes
:default_style => :medium, and
:default_url => '/images/default_image.png'
as arguments as well - if you wanted to show some kind of default image rather than eliminating the image tag entirely a la #Voyta's solution.
From the little i get ur question may following code will help you.
<% div_for post do %>
<% end unless post.blank? %>