cannot update paperclip image in active admin nested form - ruby-on-rails

I have models product and product images. Product_images is a paperclip model. Product has many product_images. I am making an Active Admin form which uploads multiple images and shows these images to the Products view page.
However, when I save the product. The product table is updated, but not the product_image table. Image attaching normally, but I can't update fields of already uploaded image.
class Product < ActiveRecord::Base
attr_accessible :name, :product_images_attributes
has_many :product_images, :dependent => :destroy
accepts_nested_attributes_for :product_images, :reject_if => lambda { |t| t['product_image'].nil? }, :allow_destroy => true
end
class ProductImage < ActiveRecord::Base
attr_accessible :name, :style
attr_accessible :image
belongs_to :product
has_attached_file :image, :styles => { :small => "150x150>", :large => "320x240>" }
validates_attachment_presence :image
end
ActiveAdmin.register Product do
form :html => { :multipart => true } do |f|
f.inputs "Admin Details" do
f.input :name
end
f.inputs "Product images" do
f.has_many :product_images do |p|
p.input :style, :as => :select, :collection => Image::STYLES, :include_blank => false
p.input :image, :as => :file, :label => "Image",:hint => p.object.image.nil? ? p.template.content_tag(:span, "No Image Yet") : p.template.image_tag(p.object.image.url(:small))
p.input :_destroy, :as=>:boolean, :required => false, :label => 'Remove image'
end
end
f.buttons
end
UPDATE
In the products model I do:
after_update :check
def check
if ProductImage.find_by_product_id(self.id).changed?
raise "image"
else
raise "fail"
end
end
and it's alway raise "fail"

I got the same error using rails 4.1. Just solved this.
I noticed that warnings in my output:
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
Unpermitted parameters: _destroy, id
So I just passed them to permit_params:
permit_params assets_attributes: [:image, :image_file_name, :image_content_type, :image_file_size, :image_updated_at, :_destroy, :id]
to AA's resource page. And it worked.
I hope it will help.
If not - here is my listings.
ActiveAdmin.register Product do
permit_params :name, :description, :price, :brand_id, :category_id, assets_attributes: [:image, :image_file_name, :image_content_type, :image_file_size, :image_updated_at, :_destroy, :id]
form multipart: true do |f|
f.inputs "Детали" do
f.input :category_id, as: :select, collection: Category.all, include_blank: false
f.input :brand_id, as: :select, collection: Brand.all, include_blank: false
f.input :name
f.input :description
f.input :price
end
f.inputs 'Фотографии' do
f.has_many :assets, allow_destroy: true, heading: 'Фото', new_record: false do |fasset|
fasset.input :image, as: :file, hint: fasset.template.image_tag(fasset.object.image.url(:thumb))
end
end
f.actions
end
end
class Product < ActiveRecord::Base
belongs_to :category
belongs_to :brand
has_many :assets, dependent: :destroy, autosave: true
accepts_nested_attributes_for :assets, allow_destroy: true,
:reject_if => lambda { |attributes| attributes[:image].blank? }
validate :name, presence: true
validate :description, presence: true
validate :price, presence: true
end
class Asset < ActiveRecord::Base
belongs_to :product
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
validates_with AttachmentPresenceValidator, :attributes => :image
end

You can configure ActiveRecord to cascade-save changes to items in a collection for a model by adding the :autosave => true option when declaring the association.
Try:
has_many :product_images, :dependent => :destroy, :autosave => true
Also, you can save the table data on association in the after_save callback like this:
class Product < ActiveRecord::Base
attr_accessible :name, :product_images_attributes
has_many :product_images, :dependent => :destroy
accepts_nested_attributes_for :product_images, :reject_if => lambda { |t| t['product_image'].nil? }, :allow_destroy => true
after_save :do_product_image_update
private
def do_product_image_update
self.product_images.save
end
end

Related

Rails 5.2: Active Admin Has_One Relations Error

I have model of course, every course has many units, every unit has many videos and has one quiz and finally every quiz has many questions.
When I try to add new course or edit one, this is the error I get:
undefined method `has_one' for #
Did you mean? has_many
This are my models:
Course.rb
class Course < ApplicationRecord
validates_presence_of :title
validates_presence_of :author
has_many :units, dependent: :destroy, autosave: true
accepts_nested_attributes_for :units, allow_destroy: true
acts_as_paranoid
end
Unit.rb
class Unit < ApplicationRecord
validates_presence_of :name
validates_presence_of :course_id
belongs_to :course
has_many :videos, dependent: :destroy, autosave: true
has_one :quiz, dependent: :destroy, autosave: true
accepts_nested_attributes_for :videos, allow_destroy: true
accepts_nested_attributes_for :quiz, allow_destroy: true
acts_as_paranoid
end
Video.rb
class Video < ApplicationRecord
validates :data ,presence: true
validates_presence_of :unit
validates_presence_of :unit_id
validates_presence_of :name
belongs_to :unit
acts_as_paranoid
end
Quiz.rb
class Quiz < ApplicationRecord
validates_presence_of :name
validates_presence_of :unit
validates_presence_of :unit_id
belongs_to :unit
has_many :questions, :dependent => :destroy, :autosave => true
accepts_nested_attributes_for :questions, allow_destroy: true
acts_as_paranoid
end
Question.rb
class Question < ApplicationRecord
validates :question ,presence: true
validates :answer1 ,presence: true
validates :answer2 ,presence: true
validates :answer3 ,presence: true
validates :answer4 ,presence: true
validates :correct ,presence: true
validates_presence_of :segment
belongs_to :quiz
acts_as_paranoid
end
This is the courses.rb in active admin:
ActiveAdmin.register Course do
permit_params :id, :title, :author, :course_details, :course_expectations, :course_time, :course_topics, :course_additional_resources,
units_attributes: [:id, :name, :_destroy, :_create, :_update,
videos_attributes: [:id, :name, :data],
quiz_attributes: [:id, :name,
questions_attributes: [:id, :question, :answer1, :answer2, :answer3, :answer4, :correct, :_destroy, :_create, :_update]]]
config.sort_order = 'id_asc'
active_admin_paranoia
# /admin/course/:id/units
member_action :units do
#units = resource.units
# This will render app/views/admin/courses/units.html.erb
end
index do
column :id
column :title
column :author
actions
end
show do
panel "About this course" do
div do
label "Course Topics:"
span course.course_topics
end
div do
label "Course Expectations:"
span course.course_expectations
end
div do
label "Time:"
span course.course_time
end
div do
label "Additional Resources:"
span course.course_additional_resources
end
end
panel "Course Overview" do
table_for course.units do
column "Unit name", :name
column(:videos) {|unit|
table_for unit.videos do
column :id
column :name
column :data
end
}
column(:quiz) { |unit|
if unit.quiz
table_for unit.quiz do
column :id
column :name
column :question
column :answer1
column :answer2
column :answer3
column :answer4
column :correct
end
else
'No Quiz'
end
}
end
end
active_admin_comments
end
sidebar "Course Units", only: :show do
# sidebar "Course Details", only: :show do
# attributes_table_for course do
# row :title
# row :author
# end
table_for Unit.joins(:course).where(:course_id => course.id) do |t|
t.column("Title") { |unit| unit.name }
end
end
form do |f|
tabs do
tab 'Basic Info' do
f.inputs "Course details" do
f.input :title
f.input :author
f.input :course_topics
f.input :course_expectations
f.input :course_time
f.input :course_additional_resources
end
end
tab 'Content' do
f.inputs "Units" do
f.has_many :units, heading: false, allow_destroy: true do |unit|
unit.input :name
unit.has_many :videos, heading: false, allow_destroy: true do |video|
video.input :name
video.input :data, label: 'Url', :as => :string, input_html: { class: 'video-tab' }
end
unit.has_one :quiz, heading: false, allow_destroy: true do |quiz|
quiz.has_many :questions, heading: false, allow_destroy: true do |q|
q.input :question, input_html: { class: 'quiz-tab' }
q.input :answer1, input_html: { class: 'quiz-tab' }
q.input :answer2, input_html: { class: 'quiz-tab' }
q.input :answer3, input_html: { class: 'quiz-tab' }
q.input :answer4, input_html: { class: 'quiz-tab' }
q.input :correct, input_html: { class: 'quiz-tab' }, as: :select, collection: [1,2,3,4]
end
end
end
end
end
end
f.actions
end
end

undefined method `event_id' when using a belongs_to/has_many association

I'm creating a site that has events. Each event acts as a gallery and has_many images. Each image belongs_to and event.
I followed the RailsCast #253 CarrierWave gem. When I try to add a new image, it says
undefined method `event_id' for # Image:0x7302438
<%= form_for #image, :html => {:multipart => true} do |f| %>
<%= f.error_messages %>
<%= f.hidden_field :event_id %>
<%= f.label :title %><br />
<%= f.text_field :title %>
Here is my image.rb
class Image < ActiveRecord::Base
attr_accessible :event_id, :title, :image
validates :title, :image, :presence => :true, :uniqueness => :true
belongs_to :event
mount_uploader :image, ImageUploader
end
and the event.rb
class Event < ActiveRecord::Base
attr_accessible :title, :date, :about
validates :title, :about, :date, :presence => :true
validates :title, :uniqueness => :true
has_many :images
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
end
Running this in a migration worked. Column wasn't added.
def up
change_table :images do |t|
t.references :event
end
end

Ruby, Paperclip, Formtastic, ActiveAdmin and images

How do I create a form in Paperclip, ActiveAdmin, and Formtastic? The image is not part of the model, but part of a sub-model.
I tried:
form :html => {:multipart => true} do |f|
f.inputs "Ticket Info" do
...
f.input :image1.photo
f.input :image2.photo
But it gave an error ActionView::Template::Error (undefined method 'photo' for :image1:Symbol):.
Here is the Ticket model:
class Ticket < ActiveRecord::Base
attr_accessible ... :image1_id, :image2_id
...
belongs_to :image1, class_name: "TicketImage"
belongs_to :image2, class_name: "TicketImage"
Here is the TicketImage model:
class TicketImage < ActiveRecord::Base
attr_accessible :file, :photo
has_one :ticket
has_attached_file :photo, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
end
I also tried f.input :image1 but it just gave me an empty select box.
I also tried f.input :image1, :as => :file, but it gave me this error after I selected a file and clicked submit:
ActiveRecord::AssociationTypeMismatch in Admin::TicketsController#update
TicketImage(#89768376) expected, got ActionDispatch::Http::UploadedFile(#29533068)
I also tried
f.semantic_fields_for :image1 do |image|
image.input :photo, :as => :file, :name => "Image1"
end
f.semantic_fields_for :image2 do |image|
image.input :photo, :as => :file, :name => "Image2"
end
but it only gave one file select button labeled Photo, and after I submitted, gave this error:
ActiveRecord::AssociationTypeMismatch in Admin::TicketsController#update
TicketImage(#86546820) expected, got ActiveSupport::HashWithIndifferentAccess(#20656416)
I also tried this: Added:
ActiveAdmin.register Ticket do
...
f.input :photo, :as => :file, :for => :image1, :name => "Image 1"
class Ticket < ActiveRecord::Base
attr_accessible ... :image1_id, :image2_id, :image1_attributes, ...
accepts_nested_attributes_for :image1, :image2, :allow_destroy => true
class TicketImage < ActiveRecord::Base
attr_accessible :file, :photo, :photo_file_name, :photo_content_type, :photo_file_size, :photo_updated_at
And the file upload box appears and accepts an upload, but in the log, it says:
WARNING: Can't mass-assign protected attributes: photo
I also tried this, which works with ONE upload field, but when both are put in the form, NEITHER are displayed! There are no errors in the server log either:
f.semantic_fields_for :image1 do |image|
image.input :photo, :as => :file, :name => "Image1", :hint => image.object.nil? ? "No Image" : f.template.image_tag(image.object.photo.url(:thumb))
end
# f.semantic_fields_for :image2 do |image|
# image.input :photo, :as => :file, :name => "Image2", :hint => image.object.nil? ? "No Image" : f.template.image_tag(image.object.photo.url(:thumb))
# end
I also tried this, which seems to works all the way and save images, except it allows you to create one-to-many association with the image1 field, which is only a single entry! I haven't tried adding two images to image1, but I expect it to crash.
f.has_many :image1 do |p|
p.input :photo, :as => :file, :label => "Image 1", :hint => p.template.image_tag(p.object.photo.url(:thumb))
p.input :_destroy, :as=>:boolean, :required => false, :label => 'Remove image'
end
f.has_many :image2 do |p|
p.input :photo, :as => :file, :label => "Image 2", :hint => p.template.image_tag(p.object.photo.url(:thumb))
p.input :_destroy, :as=>:boolean, :required => false, :label => 'Remove image'
end
This works the best, but hints don't work!
f.inputs :photo, :as => :file, :for => :image1, :name => "Image 1", :hint => "A Hint"
f.inputs :photo, :as => :file, :for => :image2, :name => "Image 2", :hint => "A Hint"
Nested forms are also supported by Formtastic:
form :html => {:multipart => true} do |f|
f.input :number
f.semantic_fields_for :image1 do |image|
image.input :photo, :name => "Image1"
f.semantic_fields_for :image2 do |image|
image.input :photo, :name => "Image2"

Active admin multiple file/image upload with paperclip

I use Active admin and I need upload Galleries with a lot of images. How can I do it?
My code:
class Gallery < ActiveRecord::Base
belongs_to :event
has_many :images
attr_accessible :name, :publish, :images, :image, :images_attributes
accepts_nested_attributes_for :images, allow_destroy: true
validates :name, presence: true
end
class Image < ActiveRecord::Base
belongs_to :gallery
attr_accessible :url
has_attached_file :url, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
ActiveAdmin.register Gallery do
form html: { multipart: true } do |f|
f.inputs do
f.input :name
f.input :images, as: :file, input_html: { multiple: true}
end
f.buttons
end
end
And I have this error:
Image(#70319146544460) expected, got ActionDispatch::Http::UploadedFile(#70319105893880)
Try this:
ActiveAdmin.register Gallery do
form multipart: true do |f|
f.inputs do
f.input :name
f.has_many :images do |p|
p.input :url
end
end
f.actions
end
end
Okay, I managed to solve it:
Try to do the following:
ActiveAdmin.register Gallery do
form html: { multipart: true } do |f|
f.inputs do
f.input :name
file_field_tag("gallery_images_url", multiple: true, name: "gallery[gallery_images_attributes][][url]")
end
f.buttons
end
end
I got to that solution by following this blog post: http://www.tkalin.com/blog_posts/multiple-file-upload-with-rails-3-2-paperclip-html5-and-no-javascript

Is it possible to do deep nesting in active admin?

It's the third day I'm crushing on Active Admin.
I have #survey that has_many :questions and each question has_many :answers - they are actually variants users can choose from.
But still I cant put it to work, it just doesn't create anything deeper then 1 level:
even the form works properly, but nothing is created.
I have the following clases Course->Sections->Lessons.
I did the following:
form do |f|
f.inputs "Details" do
f.input :instructor, :as => :select
f.input :title
f.input :name
f.input :price
f.input :discount
f.input :slug
f.inputs "Sections" do
f.has_many :sections, :header=>"" do |section|
section.input :name
section.input :position
if section.object.id
section.input :_destroy, :as=>:boolean, :required => false, :label=>'Remove'
end
section.has_many :lessons, :header=>"Lessons" do |lesson|
lesson.input :title
lesson.input :position
lesson.input :duration
lesson.input :_destroy, :as=>:boolean, :required => false, :label=>'Remove'
end
end
end
end
f.buttons
end
My models are as follow:
class Course < ActiveRecord::Base
has_many :sections, :dependent => :delete_all
accepts_nested_attributes_for :sections, :allow_destroy => true
attr_accessible :sections_attributes
....
class Section < ActiveRecord::Base
belongs_to :course
has_many :lessons, :dependent => :delete_all
attr_accessible :course_id, :name, :position
accepts_nested_attributes_for :lessons, :allow_destroy => true
attr_accessible :lessons_attributes
....
class Lesson < ActiveRecord::Base
belongs_to :section
attr_accessible :duration, :position, :section_id, :title
....
And it works great! I don't know what happens if I go more levels deeper.

Resources