1

I am setting up a blogging-type platform where a user can create an account, and that user has many posts, which should show up on the user/show page. I already had the posts and users tables set up, and added in the belongs_to & has_many relationships after the fact. When I submit the form, it alerts that "User account updated" but the post does not show up in the posts table. I think I must be missing something crucial.

Schema.rb

  create_table "posts", force: true do |t|
    t.text     "title"
    t.text     "body"
    t.string   "category1"
    t.string   "category2"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "image"
    t.integer  "user_id"
    t.integer  "category_id"
  end

  add_index "posts", ["category_id"], name: "index_posts_on_category_id", using: :btree
  add_index "posts", ["user_id"], name: "index_posts_on_user_id", using: :btree

  create_table "users", force: true do |t|
    t.string   "email"
    t.string   "password_digest"
    t.boolean  "admin"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

Model

class User < ActiveRecord::Base
  has_many :posts
  accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
end

Controller

class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]

  # GET /users
  # GET /users.json
  def index
    @users = User.all
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1
  # PATCH/PUT /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  # DELETE /users/1.json
  def destroy
    @user.destroy
    respond_to do |format|
      format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_params
      params.require(:user).permit(:email, :password, :password_confirmation)
    end
end

posts/new

<%= form_for current_user do |ff| %>
  <%= ff.fields_for :post do |f| %>
    <%= f.label :title %>
    <%= f.text_field :title, class: "title", placeholder: "Post Title..." %>

    <%= f.label :body %>
    <%= f.text_area :body, id: "edit" %>

    <%= f.submit %>
  <% end %>
<% end %>
2
  • What version of Rails are you using? Can you post your UsersController? Commented May 9, 2015 at 22:40
  • Rails 4.1.8 , just added the code for the users_controller. There is a posts controller as well with basically the same stuff. Commented May 10, 2015 at 22:44

3 Answers 3

1

Rails 4 uses a pattern called "strong parameters" in the controllers to determine what attributes of an object can be mass-assigned. This is at the bottom of your UsersController:

# Never trust parameters from the scary internet, only allow the white list through.
def user_params
  params.require(:user).permit(:email, :password, :password_confirmation)
end

Then notice that in the create action this is being called on the line with @user = User.new(user_params). Since you are using nested attributes to create posts along with a user, you need to whitelist the post attributes along with the permitted user attributes, which you can do by passing a hash where the key is the name of the child object and the value is an array of the attributes that need to be whitelisted for that object. Try this:

def user_params
  params.require(:user).permit(:email, :password, :password_confirmation, post: [:title, :body])
end
Sign up to request clarification or add additional context in comments.

Comments

1

I fixed this by getting rid of the fields_for block and simplifying:

# posts/new

<%= form_for @post do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title, class: "title", placeholder: "Post Title..." %>

  <%= f.label :body %>
  <%= f.text_area :body, id: "edit" %>

  <%= f.submit %>
<% end %>

and adding this line to the create method in the posts controller:

@post = Post.new post_params.merge(user_id: current_user.id)

current_user is a previously defined helper method

Comments

0

You are allowing only user parameters to store, for nested attributes also permit post parameters. Replace your user_params method with following code:

def user_params
  params.require(:user).permit(:email, :password, :password_confirmation, post_attributes: [:title, :body])
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.