Topic: Passing an instance variable into a form

This is likely an error due to my minimal understanding of Rails and how to use variables across models, so if there is more code needed to answer it or if my terminology is incorrect, let me know and I will gladly update the question.

I have a feed of posts that I want a user to be able to "like." While the following code allows likes to work on an individual post's page - site.com:3000/posts/*post.id* - with the form data being passed of "like[liked_post_id]:*post.id*", when I try to submit a like on a profile - site.com:3000/users/*user.id* - which contains a feed of posts, the form data being passed is "like[liked_post_id]:" (blank value)

How can I pass the post's ID within a feed of posts to the liked_post_id variable in _like.html.erb?

From post view:

#views/posts/_post.html.erb:
...
  <%= render 'posts/like_form' if signed_in? %>
...

Route to proper form:

#views/posts/_like_form.html.erb:
  <div id="like_form">
  <% if current_user.likes_this?(@post) %>
    <%= render "posts/unlike" %>
  <% else %>
    <%= render "posts/like" %>
  <% end %>
  </div>

Like form:

#views/posts/_like.html.erb
  <%= form_for Like.new, :remote => true do |f| %>
    <%= f.hidden_field :liked_post_id, :value => @post.id %>
    <%= f.submit "Like" %>
  <% end %>

From profile (feed of posts):

#views/users/show.html.erb
...
  <%= render @posts %>
...

Likes controller:

#controllers/likes_controller.rb    
  class LikesController < ApplicationController
  before_filter :signed_in_user

  def create
    @post = Post.find(params[:like][:liked_post_id])
    current_user.like!(@post)
    respond_to do |format|
      format.html { redirect_to root_url }
      format.js
    end
  end

User model:

#models/user.rb
...
  def like!(post)
    likes.create!(liked_post_id: post.id)
  end
...

Last edited by DiCli (2013-02-13 12:53:08)

Re: Passing an instance variable into a form

In your 'create' action the variable @post is never initialized:

def create
        @micropost = Post.find(params[:like][:liked_post_id])
        current_user.like!(@post)
        respond_to do |format|
          format.html { redirect_to root_url }
          format.js
        end
      end

You have just @micropost variable.
Second point - I don't see where the variable @post comes from in your view:

#views/posts/_like.html.erb
    <%= form_for(current_user.likes.build(liked_post_id: "#{@post.id}"),
                 remote: true) do |f| %>
      <div><%= f.hidden_field :liked_post_id %></div>
      <%= f.submit "Like", class: "btn btn-mini btn-primary" %>
    <% end %>

The principle of sharing instance variable between a controller and the view (by convention, its name corresponds to the controller's action) simple: any instance variable defined in the action is 'visible' in the view.
See more details at Rails guides.

Re: Passing an instance variable into a form

Thanks for pointing out my @micropost issue, I have resolved that and moved the like action into my Likes Controller (actually handled by the like! method in my User model).

See my new _like.html.erb file above.

I have noticed that the action of the like form is "/likes" across the board. Would this will only work when you are on the page site.com:3000/posts/*post.id* ? I'm curious if I need to modify the it so that the action of the form is "/posts/post.id/likes" when you are on the page site.com:3000/users/*user.id*

My form markup is also an issue. On a post's page the generated markup is:

<input id="like_liked_post_id" name="like[liked_post_id]" type="hidden" value="73" /> 

While on the feed page:

<input id="like_liked_post_id" name="like[liked_post_id]" type="hidden" />

Last edited by DiCli (2013-02-13 15:56:58)