***Update – this no longer works due to changes in Paperclip but leaving here for historical context. I have moved to using the gem Refile for image stuff***
So have a new web application where users will be able to upload images along with a post. I haven’t used the ruby gem Paperclip from ThoughtBot since rails 3.2 (which seems like it was only a couple months ago) so I thought I would write up a post on how I got it working.
The background of the app
- Post have many images
- Image is polymophic and can belong to either Post or Comment
So first step is to add the gem ‘paperclip’ to your gem file and then run bundle install.
Next, configure paperclip in development/production.rb For this app we will be doing file storage locally until it is live
config/enviornments/development.rb
[code]
Paperclip.options[:command_path] = "/usr/local/bin"
[/code]
After that we need to setup our models for Image and Post. Image is polymorphically related to Post as imageable and also contains content through the paperclip gem. Post has images and can accept nested attributes for images.
app/models/image.rb
[code]
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
has_attached_file :content, :styles=>{:medium => "300×300>", :thumb => "100×100>"}
validates_attachment_content_type :content, :content_type => %w(image/jpeg image/jpg image/png)
end
[/code]
app/models/post.rb
[code]
class Post < ActiveRecord::Base
belongs_to :user
has_many :images, :as => :imageable, dependent: :destroy
accepts_nested_attributes_for :images
end
[/code]
Now that the models are good, we have to code around the strong parameters that were added in rails 4. Notice that in the private section we are adding ‘images_attributes: [:content]’ to prevent the image upload from being filtered and adding @post.images.build to the new action so that our view can render out the file tag properly.
app/controllers/posts_controller.rb
[code]
class PostsController < ApplicationController
def new
@post = Post.new
@post.images.build
end
def create
@post = Post.new(post_params)
@post.user_id = current_user.id
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: ‘Post was successfully created.’ }
format.json { render action: ‘show’, status: :created, location: @post }
else
format.html { render action: ‘new’ }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
private
#strong parameters
def post_params
params.require(:post).permit(:title, :description, images_attributes: [:content])
end
end
[/code]
Last part is the view, now that it is wired up it will just be adding a couple lines to our form. I removed the code that will spit out the errors that come through for succinctness here. Note that the upload image part has :images in fields_for which corresponds to our has_many :images in Post model and that the file_file :content corresponds to the has_attached_file :content in our Image mode.
Also, in order for the html field to accept images, make sure you add the multipart to the html.
app/views/posts/_form.html.erb
[code]
<%= form_for @post, :html => { :multipart => true } do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<div>
Upload Image
<%= f.fields_for :images do |ph| %>
<%= ph.file_field :content %>
<% end%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
[/code]
That about does it. If you put this together and it doesn’t work, restart your server and it should start singing.