简体   繁体   中英

rails ajax overwriting all partials when refreshing page

I was making a simple variation of the simple example of ajax in rails: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example

I am trying to create a user show view in which new posts are created upon pressing a button. These posts are all listed below the user on the same show page and appear upon creation.

The posts are created fine and shown correctly on the page, however when I refresh the page my

  @post = User.posts.build() 

Overwrites all the previously created posts giving each of them a nul id. Also, is it correct to place the create.js.erb in the views folders, or should it go in the assets/javascripts folder?

Here are my files:

UsersController

def show
    @user = User.find(params[:id])
    @posts = Post.all
    @post = @user.posts.build
end

users/show.html.erb

<%= "user-id: #{@user.id}" %>

<ul id="posts">
<%= render :partial => @posts %>
</ul>


<%= form_for(@post, remote: true) do |f| %>
  <%= f.hidden_field :user_id, :value => @user.id %>
  <%= f.submit %>
<% end %>

PostsController

def create
  puts params[:post][:user_id]
  @user = User.find(params[:post][:user_id])
  puts @user
  @post = @user.posts.build()
  respond_to do |format|
    if @post.save
      format.html { redirect_to @post, notice: 'Post was successfully created.' }
      format.js   {}
      format.json { render json: @post, status: :created, location: @post }
    else
      format.html { render action: "new" }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
    Rails.logger.info(@post.errors.inspect) 
  end
end

def index
    @posts = Post.all
    @post = Post.new
end

posts/_post.html.erb

 <li><%= @post.id %></li>

posts/create.js.erb

 $("<%= escape_javascript(render @post) %>").appendTo("#posts");

Found a workaround by avoiding the use of the _post partial to display the older posts:

edit: users/show.html.erb

<ul id="posts">
  <% @posts.each do |post| %>
    <li>
      <%= post.id %>
    </li>
  <% end %>
</ul>

I don't think this is an ideal solution but it works fine for now.

The Problem

The reason why your partial is rendering all new posts is because you are using the instance variable @post instead of the local variable post inside your partial.

In your UsersController#show action, you set @post = @user.posts.build . When you render <%= @post.id %> inside the partial, you are referencing that same variable which comes from the controller and was set to a new post.

It seems that all the previously created posts are being "null'ed" out, but it's really just that you are continuously rendering a new post, not the existing ones.

The Solution

You need to update your partial to use a local variable , not the instance variable .

<li><%= post.id %></li>

This local variable is automatically provided to you by Rails when you render a collection of records like this

<%= render @user.posts %>

or alternatively

<%= render partial: "posts/post", collection: @user.posts %>

How to Avoid in the Future

This is a really common mistake and can be easy to miss.

For this reason, my recommendation is to stop using instance variables in partials altogether.

Resources

Yes, you are correct.

create.js.erb with the suffix erb to help you add code ruby to it.

Write code in this file the same with you write javascript code on view html.erb with syntax

<script>
  $("<%= escape_javascript(render @post) %>").appendTo("#posts");
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM