Wordica
Wordica

Reputation: 2595

Rails 6.1.3.2 Unpermitted parameter and User must exist

Few years ago I develop aps in Rails 4 and now many things change.

I user Shire GEM in this example to upload photos:

Ok, my models:

Photo model:

class Photo < ApplicationRecord

    include ImageUploader::Attachment(:image)

    belongs_to :user

end

User model ( i put only few lines):

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :validatable
    

  has_one :profile, :dependent => :destroy
  has_many :photos, :dependent => :destroy

end

PhotosController:

class PhotosController < ApplicationController

    before_action :set_photo, only: %i[ show edit update destroy ]
    before_action :authenticate_user!

 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 :show, status: :created, location: @photo }
    else
       format.html { render :new, status: :unprocessable_entity }
       format.json { render json: @photo.errors, status: :unprocessable_entity }
    end
 end

private
    # Use callbacks to share common setup or constraints between actions.
    def set_photo
       @photo = Photo.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def photo_params
      params.require(:photo).permit(:title, :image_data, :image, :user_id)
    end


 end

    

UsersController:

class UsersController < ApplicationController


  private

  # Only allow a list of trusted parameters through.

     def set_user
       @user = User.find(params[:id])
     end

     def user_params
       params.require(:user).permit(:id)
     end

 end

And now last thing, form for add photos in view:

 <%= form_with(model: photo) do |form| %>
   <% if photo.errors.any? %>
     <div id="error_explanation">
      <h2><%= pluralize(photo.errors.count, "error") %> prohibited this photo from being saved:</h2>

      <ul>
         <% photo.errors.each do |error| %>
           <li><%= error.full_message %></li>
         <% end %>
      </ul>
     </div>
   <% end %>

   <div class="field">
     <%= form.label :title %>
     <%= form.text_field :title %>
   </div>

   <div class="field">
     <%= form.label :image %>
     <%= form.file_field :image %>
   </div>
   <%= current_user.id %> // SHOWS USER ID

   //// THIS GENERATE ERROR ////
   <%#= form.hidden_field :user_id => current_user.id %>

   <div class="actions">
     <%= form.submit %>
   </div>
 <% end %>

And where I have problem. When I to it in that way I see in logs unpermited parameters :user_id.

But when I submit form I see error "User must exist".

I found solution and change in PhotosController this line:

def create
   @photo = Photo.new(photo_params)

to:

def create
   @photo = current_user.photos.new(photo_params)

and it start working. Photo have user_id in table. But I want to know why I can't add user_id for photos in form in view like:

 <%= form.hidden_field :user_id => current_user.id %>

Upvotes: 0

Views: 430

Answers (1)

max
max

Reputation: 102222

Never pass the user id as plaintext through the parameters. Get it from the session instead. Its trivial for any malicous user to use the web inspector and simply fill in the hidden input and then upload a unseemly picture as ANY user.

The session cookie is encrypted and much more difficult to tamper with.

class PhotosController < ApplicationController
  before_action :authenticate_user!
  
  def create
    # build the record off the current_user
    @photo = current_user.photos.new(photo_params)
    respond_to do |format|
      if @photo.save
        format.html { redirect_to @photo, notice: "Photo was successfully created." }
        format.json { render :show, status: :created, location: @photo }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @photo.errors, status: :unprocessable_entity }
      end
    end
  end 
  
  private
  # Only allow a list of trusted parameters through.
  def photo_params
    params.require(:photo).permit(:title, :image_data, :image)
  end
end

But I want to know why I can't add user_id for photos in form in view like:

<%= form.hidden_field :user_id => current_user.id %>

Because you're calling the method with the wrong arguments. The signature is hidden_field(object_name, method, options = {}) but as already stated its a bad idea.

Upvotes: 1

Related Questions