Reputation: 377
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");
Upvotes: 0
Views: 107
Reputation: 7434
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.
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 %>
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.
Upvotes: 1
Reputation: 377
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.
Upvotes: 1
Reputation: 543
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>
Upvotes: 0