Skip to content

Instantly share code, notes, and snippets.

@madwork
Last active July 25, 2021 09:13
Show Gist options
  • Save madwork/7356782 to your computer and use it in GitHub Desktop.
Save madwork/7356782 to your computer and use it in GitHub Desktop.
Polymorphic attachments with CarrierWave and nested_attributes
class Attachment < ActiveRecord::Base
mount_uploader :attachment, AttachmentUploader
# Associations
belongs_to :attached_item, polymorphic: true
# Validations
validates_presence_of :attachment
validates_integrity_of :attachment
# Callbacks
before_save :update_attachment_attributes
# Delegate
delegate :url, :size, :path, to: :attachment
# Virtual attributes
alias_attribute :filename, :original_filename
private
def update_attachment_attributes
if attachment.present? && attachment_changed?
self.original_filename = attachment.file.original_filename
self.content_type = attachment.file.content_type
end
end
end
# encoding: utf-8
require 'carrierwave/processing/mime_types'
class AttachmentUploader < CarrierWave::Uploader::Base
include CarrierWave::MimeTypes
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
process :set_content_type
end
class AttachmentsController < ApplicationController
before_action :find_attachable
def create
@attachable.attachments.create attachment_params
redirect_to @attachable
end
private
def attachment_params
params.require(:attachment).permit(:attachment)
end
# could be improve and include into concerns
# http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
def find_attachable
params.each do |name, value|
return @attachable = $1.classify.constantize.find(value) if name =~ /(.+)_id$/
end
end
end
# Required gem ryanb/nested_form
# https://github.com/ryanb/nested_form
<%= nested_form_for @post, html: { multipart: true } do |f| %>
<p><%= f.link_to_add "Add an attachment", :attachments %></p>
<%= f.fields_for :attachments do |attachment_form| %>
<%= attachment_form.file_field :attachment %>
<%= attachment_form.hidden_field :attachment_cache %>
<%= attachment_form.link_to_remove "Remove this attachment" %>
<% end %>
<% end %>
class Post < ActiveRecord::Base
has_many :attachments, as: :attached_item, dependent: :destroy
# http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for
accepts_nested_attributes_for :attachments, allow_destroy: true, reject_if: proc { |attributes| attributes[:attachment].nil? }
end
class PostsController < ApplicationController
def new
@post = Post.new
end
def create
@post = Post.create post_params
redirect_to @post
end
private
def post_params
params.require(:post).permit(attachments_attributes: [:id, :attachment, :attachment_cache, :_destroy])
end
end
App::Application.routes.draw do
# Concerns must be declared before
# http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Concerns.html
concern :attachable do
resources :attachments, only: :create
end
resources :posts, concerns: [:attachable]
end
create_table "attachments", force: true do |t|
t.integer "attached_item_id"
t.string "attached_item_type"
t.string "attachment", null: false
t.string "original_filename"
t.string "content_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "attachments", ["attached_item_type", "attached_item_id"]
@acrolink
Copy link

Does this code apply to Rails 5. I have tried this code but nothing gets stored in the database.

@potatowave
Copy link

potatowave commented Sep 17, 2017

Works for me. My only challenge is I added a "Description" and "Order" to my attachments table. I'm trying to figure out how to 'edit' those fields with an edit view/update model without actually uploading a new image. (works if you update the image too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment