0

I am trying to add a polling feature to the app from Hartl's Rails Tutorial. Started off by following #196 Nested Model Form and Nested forms with Rails 4.2 Strong Parameters. After submitting the form, the content saves properly to the database, however, I am unable to see the results in the show page and cannot figure out why.

Models-

class Micropost < ActiveRecord::Base
  has_many :polls, dependent: :destroy
  accepts_nested_attributes_for :polls, :reject_if => lambda {|a| a[:content].blank? } 

  def questions_for_form
    collection = polls.where(micropost_id: id)
    collection.any? ? collection : polls.build
  end
end

class Poll < ActiveRecord::Base
  belongs_to :micropost
  has_many :answers, dependent: :destroy
  accepts_nested_attributes_for :answers, :reject_if => lambda {|a| a[:content].blank? }

  def answers_for_form
    collection = answers.where(micropost_id: id)
    collection.any? ? collection : answers.build
  end
end

class Answer < ActiveRecord::Base
  belongs_to :poll
end

Controllers-

class StaticPagesController < ApplicationController
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      @poll = @micropost.polls.build
        3.times {@poll.answers.build}
      @feed_items = current_user.feed.paginate(page: params[:page])
    end
  end
end

class MicropostsController < ApplicationController
  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content, polls_attributes: [:content, :id, :micropost_id, answers_attributes: [:content, :id, :poll_id]])
    end
end

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    @microposts = @user.microposts.paginate(page: params[:page])
  end
end

Routes-

Rails.application.routes.draw do
  resources :microposts,          only: [:create, :destroy]
  resources :polls
  resources :answers
end

Views-

_micropost_form.html.erb

<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new post..." %>
  </div>

  <button type="button" class="btn btn-default btn-xs" data-toggle="collapse" data-target="#pollcollapse" id="pollbtn">Poll</button>

  <div id="pollcollapse" class="collapse">
  <%= f.fields_for :polls do |questions_for_form| %>
    <%= render 'shared/poll_fields', :f => questions_for_form %>
  <% end %>
  </div>

  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

_poll_fields.html.erb

<div class="field">
  <%= f.text_field :content, placeholder: "Poll question..."  %>
</div>

<%= f.fields_for :answers do |answers_for_form| %>
  <%= render 'shared/answer_fields', :f => answers_for_form %>
<% end %>

_answer_fields.html.erb

<div>
  <%= f.text_field :content, placeholder: "Answer" %>
</div>

show.html.erb

<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
  <div class="col-md-8">
    <% if @user.microposts.any? %>
      <h3>Posts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
</div>

_micropost.html.erb

<li id="micropost-<%= micropost.id %>">

  <span class="content"><%= micropost.content %></span>

  <span>
    <% for poll in @micropost.polls %>    //Poll & answer content do not appear.
        <%= poll.content %>
        <% for answer in poll.answers %>
          <%= answer.content %>
        <% end %>
    <% end %>
  </span>

</li>

I think this should be all of the relevant information, but please let me know if I am missing anything. Thank you very much for any help at all!

chrxtina
  • 43
  • 6

2 Answers2

0

In your _micropost.html.erb partial, you reference @micropost which doesn't appear to be defined anywhere. Try changing that from an instance variable to tbe local variable micropost (learn about the difference between @micropost and micropost here). Also, in Ruby it's recommended by people smarter than me (at least I've read it multiple times) that you should use .each instead of for. The updated code in your partial:

<li id="micropost-<%= micropost.id %>">

  <span class="content"><%= micropost.content %></span>

  <span>
    <% micropost.polls.each do |poll| %>
        <%= poll.content %>
        <% poll.answers.each do |answer| %>
          <%= answer.content %>
        <% end %>
    <% end %>
  </span>

</li>

Also, since you define @microposts in your show action, you can refactor your code in the show view like so:

<div class="col-md-8">
    <% if @microposts.any? %>
      <h3>Posts (<%= @microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
Community
  • 1
  • 1
John
  • 9,249
  • 5
  • 44
  • 76
  • Thanks for your help, @John. I updated the post to include what I previously had for my controller's show action as well as the full show page. I know that the content from a micropost successfully gets created and is displayed, however, it is just the content from the nested form within the micropost that is not showing up. I tried adding `@polls = @micropost.polls` and `@answers = @polls.answers` but was not successful. I previously assumed that they weren't necessary bc other nested forms (links above) didn't include child elements in the show action, but maybe I'm using the wrong code. – chrxtina Apr 14 '16 at 06:29
  • It doesn't look like you have `@micropost` defined anywhere. Try changing `@micropost` to `micropost` (remove the `@`) in your `_micropost` partial. Also, while I don't think it's affecting you, I've read in multiple places that, in general, you should use `.each` instead of `for` in ruby. The different between them is summed up in this S.O. answer: http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby. I'll update my answer to include the exact code change – John Apr 14 '16 at 16:40
  • One other thing, this is just an opinion so I'm including it as a comment, but I've done a lot with nested forms / `accepts_nested_attributes_for` / `fields_for` in my own app and, after learning about the excellent Reform gem, I WISH I had used that. It looks like you already have this code almost working, but if you'll be doing more work with nested forms I'd seriously consider making the switch to that gem. https://github.com/apotonick/reform – John Apr 14 '16 at 16:57
  • Awesome, thank you so much, @John! Your changes worked for me. I guess that I have more studying to do on instance vs. local variables. – chrxtina Apr 14 '16 at 20:52
  • In this situation, the problem is that `@micropost` is a different variable then `micropost` much like `a` is a different variable than `b`. (assuming you don't set them equal to one another) – John Apr 14 '16 at 21:01
0

Yes instance vs. Local variables issue. I'd say it might be easier to use a gen, but if you are learning rails and you have the time, my opinion is its better to do it yourself the first time. It helps you learn the framework and better able to solve problems when you run into something for which there is no gem. After learning yourself, go with a gem if you find it really serves your purpose... Or make your own gem! Cheers.

Focorunner
  • 56
  • 3