3

I have follow Michael Hartl's tutorial and now I want to add photos to microposts. But when I submit microposts, the image isn't saved in the database and in the dvlpmt log I can read unpermitted parameters :image I have look in other posts and did what they advice but it doesn't work for me.

MODELS

micropost.rb

class Micropost < ActiveRecord::Base
  belongs_to :user
  has_one :photo
  default_scope -> { order('created_at DESC') }
  validates :content, presence: true, length: { maximum: 140 }
  validates :user_id, presence: true
end

photo.rb

class Photo < ActiveRecord::Base
    belongs_to :micropost
    has_attached_file :image
end

CONTROLLERS

photos_controller.rb

class PhotosController < ApplicationController
  before_action :signed_in_user, only: [:create, :destroy, :index]
  
  def create
    @photo = Photo.new(photo_params)

    respond_to do |format|
      if @photo.save
        format.html { redirect_to @photo, notice: 'Photo was successfully created.' }
        format.json { render action: 'static_pages/home', status: :created, location: @photo }
      else
        format.html { render action: 'static_pages/home' }
        format.json { render json: @photo.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    def photo_params
      params.require(:photo).permit(:image)
    end
end

microposts_controller.rb

class MicropostsController < ApplicationController
  before_action :signed_in_user, only: [:create, :destroy]
  
  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end
  
  private

  def micropost_params
    params.require(:micropost).permit(:content, photo_attributes: [:photo_id, :image])
  end
end

VIEWS

_micropost_form.html.erb I dont know how to construct well this form, I've tried a lot of different formulations

<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>

  <%= f.fields_for :image, :html => { :multipart => true } do |builder| %>
    <%= f.file_field :image, :f => builder %>
  <% end %>

  <%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>

And when I want to submit my form, it is ok, but the column "photo_id" is empty for the table micropost. And photo isn't saved in the database.

Server log

Started POST "/microposts" for 127.0.0.1 at 2013-11-27 15:06:06 +0100
Processing by MicropostsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"<my_private_token>", "micropost"=>{"content"=>"Hello world", "image"=>#<ActionDispatch::Http::UploadedFile:0x00000003401a48 @tempfile=#<Tempfile:/tmp/RackMultipart20131127-4010-1r6qt80>, @original_filename="paint.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"micropost[image]\"; filename=\"paint.jpg\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Post"}
  [1m[36mUser Load (0.2ms)[0m  [1mSELECT "users".* FROM "users" WHERE "users"."remember_token" = '342df8f039f7f40698b3691f77d2539dc8b9c101' LIMIT 1[0m
Unpermitted parameters: image
  [1m[35m (0.1ms)[0m  begin transaction
  [1m[36mSQL (0.4ms)[0m  [1mINSERT INTO "microposts" ("content", "created_at", "updated_at", "user_id") VALUES (?, ?, ?, ?)[0m  [["content", "Hello world"], ["created_at", Wed, 27 Nov 2013 14:06:06 UTC +00:00], ["updated_at", Wed, 27 Nov 2013 14:06:06 UTC +00:00], ["user_id", 101]]
  [1m[35m (145.1ms)[0m  commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 153ms (ActiveRecord: 145.7ms)

I am completely stuck right now, thank you if you can find something that can help me where to find the solution!!!

Sofien
  • 1,302
  • 11
  • 21
2ueenO
  • 164
  • 1
  • 1
  • 10
  • It looks like you've got nesting like `{:micropost => {:image => ...}}`, so you'd need `params.require(:micropost).permit(:content, :image, ...)` – Farley Knight Nov 27 '13 at 14:36
  • You mean something like : `def micropost_params params.require(:micropost).permit(:content, photo_attributes: [:photo_id, :image, image_file_name, :image_content_type, :image_file_size, :image_update_at]) end` that doesnt change. :image is still unpermitted – 2ueenO Nov 27 '13 at 14:43
  • I found this post useful. http://stackoverflow.com/questions/20334124/unpermitted-parameters-error-for-permitted-attributes – Evolve Mar 06 '14 at 01:18

1 Answers1

0

You need to use accepts_nested_attributes_for in your Micropost class.

class Micropost < ActiveRecord::Base
  belongs_to :user
  has_one :photo
  accepts_nested_attributes_for :photo
  default_scope -> { order('created_at DESC') }
  validates :content, presence: true, length: { maximum: 140 }
  validates :user_id, presence: true
end

It also looks like your form was associating the image with your micropost, not with the micropost's photo. Take a look at the Ruby docs for fields_for. Can you try changing part of your form to this?

<%= f.fields_for :photo, :html => { :multipart => true } do |photo_fields| %>
  <%= photo_fields.file_field :image %>
<% end %>

If you do this, you'll need to make sure you call @micropost.build_photo in the controller action that renders the view.

I don't think you need to list photo_id in your strong parameters in microposts_controller.rb. That should get set once the records save to the database.

You can also read the Rails Guides on building complex forms. The guide talks about how to set up your model, view, and controller to handle nested attributes. Their description of strong parameters may be helpful to check out, if you haven't yet.

Michael Stalker
  • 1,357
  • 9
  • 15
  • Hi thank your for your interest!! I have tried your solution but now i have `Unpermitted parameters :photo` I have also read doc for fields_for and tried to add `accepts_nested_attributes_for :photo` but that make my form for the image disappear! – 2ueenO Nov 27 '13 at 15:06
  • I updated my answer. Try adding `accepts_nested_attributes_for` to your model. – Michael Stalker Nov 27 '13 at 15:15
  • I am trying, but as I said, my form to upload picture disappear when I had `accepts_nested_attributes_for` , i'm searching why – 2ueenO Nov 27 '13 at 15:32
  • I apologize for not reading your first comment closely enough. I should have caught that you already tried `accepts_nested_attributes_for`. It's odd that the field would disappear. If you look at the HTML source, are the elements there? That might help you determine if this is a CSS problem or a Rails problem. – Michael Stalker Nov 27 '13 at 15:36
  • Rails problem, lines are still in the view. And server log tell that the view is still rendered on the page! Maybe it is due to the fact that i am missing something about building photo in a function new in microposts controller ? (i've read that somewhere). But i thought it was done in the create function – 2ueenO Nov 27 '13 at 15:42
  • The server logs will tell you that the page rendered, but I don't think they'll tell you whether an element on the page rendered. We need to figure out whether the form is getting rendered, and is hidden by something, or whether Rails isn't rendering the HTML form at all. – Michael Stalker Nov 27 '13 at 15:45
  • I get the part of the form that doesn't concern photo! – 2ueenO Nov 27 '13 at 15:46
  • Does the field reappear as soon as you remove `accepts_nested_attributes_for`? – Michael Stalker Nov 27 '13 at 15:51
  • Yes ...! this is the problem but i really don't understand why – 2ueenO Nov 27 '13 at 16:00
  • Did you call @micropost.build_photo in your controller? See http://stackoverflow.com/questions/11769592/fields-for-disappear-when-adding-accepts-nested-attributes-for. – Michael Stalker Nov 27 '13 at 16:04
  • Yes and it doesn't work ... I think i can't solve it :( thank you for helping me – 2ueenO Nov 28 '13 at 16:00