File Uploads with Paperclip

© 2012 - 2017 thoughtbot, inc. Upcase, the design of a robot, and thoughtbot are registered trademarks of thoughtbot, inc.


This is a companion discussion topic for the original entry at https://thoughtbot.com/upcase/videos/intermediate-rails-4

I’m having a problem with when uploading an image.
undefined method `body’ for #Shout:0x007fd2e0cf3f68

def create
	shout =	current_user.shouts.create(shout_params)
	redirect_to root_path, redirect_option_for(shout)
end
private

def shout_params
	{content: content_from_params}
end

def content_from_params
	case params[:shout][:content_type]
		when "TextShout" then TextShout.new(text_shout_content_params)
		when "PhotoShout" then PhotoShout.new(photo_shout_content_params)
	end
end

def text_shout_content_params 
	params.require(:shout).require(:content).permit(:body)
end

def photo_shout_content_params 
	params.require(:shout).require(:content).permit(:image)
end

the error points to the shout_params

@Upcase Anyone please help!

@TheeGrassHopper It’s hard to tell from just that snippet, but it looks like your Shout model doesn’t have a body method because ActiveRecord may not have implemented it for you. This might mean that the database column for body is not there. If that’s the case, you’d need to generate a migration that adds body to the shouts table.

Can you paste your db/schema.rb so we can see what your database looks like? It would also be helpful if you posted the Shout code, or linked to a public repo of the code so it’s a bit easier to diagnose.

 ActiveRecord::Schema.define(version: 20171012163136) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "photo_shouts", force: :cascade do |t|
t.string "image_file_name", null: false
t.string "image_content_type", null: false
t.integer "image_file_size", null: false
t.datetime "image_updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
  end

  create_table "shouts", force: :cascade do |t|
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "content_type", null: false
t.integer "content_id", null: false
t.index ["content_id", "content_type"], name: "index_shouts_on_content_id_and_content_type"
t.index ["user_id"], name: "index_shouts_on_user_id"
  end

  create_table "text_shouts", force: :cascade do |t|
t.string "body", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
  end

  create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", null: false
t.string "encrypted_password", limit: 128, null: false
t.string "confirmation_token", limit: 128
t.string "remember_token", limit: 128, null: false
t.string "username"
t.index ["email"], name: "index_users_on_email"
t.index ["remember_token"], name: "index_users_on_remember_token"
t.index ["username"], name: "index_users_on_username", unique: true
  end

  add_foreign_key "shouts", "users"
end
class Shout < ApplicationRecord
  belongs_to :user
  belongs_to :content, polymorphic: :true
  validates :body, presence: true, length: {in: 1..144}
  validates :user, presence: true

  default_scope { order(created_at: :desc)}
  delegate :username, to: :user 

end

@catalystmediastudios thank you for looking at this

class TextShout < ApplicationRecord
    	validates :body, presence: true, length: {in: 1..144}
    end

 class PhotoShout < ApplicationRecord
	has_attached_file :image, styles: { thumb: "200x200" }

	validates_attachment :image,
	content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] },
 	size: { in: 0..10.megabytes },
 	presence: true
end

@TheeGrassHopper It’s a bit hard to tell, but I think it is because of the validates :body in Shout I think it only needs to be in the TextShout. can you remove the body validation in Shout and let me know if that works?

If that doesn’t can you paste the complete error message including the stack trace with the file names and line numbers?

Thank you very much !! That worked. I can’t believe I missed that. I watched the video a bunch of time to see what I missed and that didn’t come up!! @catalystmediastudios

You’re welcome. I’m glad that worked @TheeGrassHopper!

I get the following error when I try to post an image shout
No route matches [GET] "/shouts"

I have restarted twice now and all 3 times I hit the same roadbloack when trying to upload an image during this video. Every single time I have hit this error:

PG::NotNullViolation: ERROR: null value in column "content_id" violates not-null constraint DETAIL: Failing row contains (4, 1, 2018-07-28 08:07:15.431961, 2018-07-28 08:07:15.431961, PhotoShout, null). : INSERT INTO "shouts" ("user_id", "created_at", "updated_at", "content_type") VALUES ($1, $2, $3, $4) RETURNING "id"

The error page has this line highlighted: shout = current_user.shouts.create(shout_params)

And the shout_params are:

def shout_params
  { content: content_from_params }
end

with the contend being from:

def content_from_params
  case params[:shout][:content_type]
    when "TextShout" then TextShout.new(text_shout_content_params)
    when "PhotoShout" then PhotoShout.new(photo_shout_content_params)
  end
end
  
def text_shout_content_params
  params.require(:shout).require(:content).permit(:body) 
end

def photo_shout_content_params
  params.require(:shout).require(:content).permit(:image)
end

The terminal output shows this:

ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "content_id" violates not-null constraint

DETAIL:  Failing row contains (4, 1, 2018-07-28 08:07:15.431961, 2018-07-28 08:07:15.431961, PhotoShout, null).

: INSERT INTO "shouts" ("user_id", "created_at", "updated_at", "content_type") VALUES ($1, $2, $3, $4) RETURNING "id"):

If anyone has any ideas/suggestions, I would be so grateful!

I’m getting the same problem. I’ve noticed that the PhotoShout is not getting saved in the db.

This is a little late but here is what worked for me.

  class PhotoShout < ApplicationRecord
  has_one_attached :image
  has_attached_file :image, styles: { thumb: '200x200' }

  validates_attachment :image,
                       content_type: { content_type: ['image/jpge', 'image/gif', 'image/png'] }
                       size: { in: 0..10.megabytes },
                       presence: true
end

You’ll notice that I have the “has_one_attached” as well as the "has_attached_file.

Hello everyone, doing this tutorial everything went fine until now. Maybe someone of you can help me with this issue.

It looks somehow that paperclip is nit doing the job of giving a name. I’m correct?

I have uploaded an image of the error I’m getting. Any help would be great. Thanks in advance!

Did you solve this? I am stuck on the same issue!

Hi @elizaplowden : managed to work around this by using rails active storage (v6.0+) instead of since Paperclip was deprecated and recommended using ActiveStorage as an alternative

Installation was straightfoward (rails active_storage:install) which added the relevant tables. It persists local images to a storage directory.

for the model creation: rails g model PhotoShout image:attachment

This made the PhotoShout model with the has_one_attached macro. No additional validations were needed.
For updating image size, phto_shout view was as follows image_tag photo_shout.image.variant(resize: "250x250")

Here’s a link for more on ActiveStorage