Home > Net >  post request keeps getting denied even though It is included in parameters
post request keeps getting denied even though It is included in parameters

Time:10-02

I have a post function in my app that takes in the following parameters: a title, the content of the post, a boolean for anonymity, a boolean for graphic content and a string to record the username of the user who made the post. I have all of these fields specified in the new post form of my rails app. Unfortunately, when I go to submit the post, I receive an error saying: User must exist. This is happening because the User parameter is not getting posted even though I have added the parameter in my controller:

#app/controllers/posts_controller.rb

def post_params
  params.require(:post).permit(:title, :content, :anonymous, :graphic, :user_name);
end

My schema also has a parameter for the username:

  #db/schema.rb

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "name" # here is the parameter for name
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

I used embedded ruby to supply the name parameter in my post form:

    <div  >
      <%= form.text_field :user_name, name: :post_user_name, value:current_user.name, type: :hidden %>
    </div>

I used inspected element in my browser and it showed that the value was equal to my username so I'm stuck as to where the error is. I had a look at this tutorial where the person did a similar thing. He got the same error but he fixed it by adding another permit to his parameters in app/controllers/posts_controller.rb.

My create method looks like this:

#app/controllers/posts_controller.rb

  def create
    @post = Post.new(post_params)

    respond_to do |format|
      if @post.save
        format.html { redirect_to post_url(@post), notice: "Post was successfully created." }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

I have also added has_many :posts in my user model as well as belongs_to :user in my post model.

I am making a forum app, like reddit. I want to have an edit function for each post. The catch is that I want each user to only be able to edit their own posts, thus I need each post to 'remember' the user it was posted by.

My post table contains the following columns:

  create_table "posts", force: :cascade do |t|
    t.string "title"
    t.string "content"
    t.boolean "anonymous"
    t.boolean "graphic"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "user_name"
    t.index ["user_name"], name: "index_posts_on_user_name"
  end

When I change @post.user = current_user in my create method, to @post.user_name = current_user, I get the "User must exist" error

CodePudding user response:

Its likely that you never set the @post.user and therefore you will get a for ActiveRecord::RecordInvalid, meaning the post cant exist without a user attached.

since you are using devise you have access to a helper method called current_user (which acts as the logged in/authenticated user). If you indeed want the created post to be attached to the user who you are logged in as then all you need to do is:

def create 
  @post = Post.new(post_params)
  @post.user = current_user
  # your other code below
end

CodePudding user response:

Let start from the top here. You don't want to be setting up assocations to anything but the primary key column unless you have an extremely important reason to so. Which isn't the case here - and also your users table doesn't even have a user name.

Ditch that user_name column and input and add a user_id column to the table:

class AddUserToPosts < ActiveRecord::Migration[7.0]
  def change
    add_reference :posts, :user, null: true
    remove_index  :posts, :user_name
    remove_column :posts, :user_name
  end
end

If you want to allow posts that are not assocatiated with a user you need to make the column nullable and make the association optional:

class User < ApplicationRecord
  has_many :posts
end

class Post < ApplicationRecord
  belongs_to :user, optional: true
end

Creating resources that belong to the current user is an extremely common task and the correct way to do it is always to get the user from the session (or a token) as they are encrypted and difficult to tamper with. With Devise you do this with the current_user method.

If you instead add a hidden input with a user id or a user name you're just asking for spoofing as its trivial to input any users id with the web inspector or Postman.

def create
  @post = if user_signed_in?
    current_user.posts.new(post_params)
  else
    Post.new(post_params)
  end

  # ...
end

Make sure you do not permit the :user_id attribute in your params whitelist.

  • Related