Render a 'micropost feed' from the Rails Tutorial in a custom location/view?

358 views Asked by At

I followed Michael Hartl's 'Rails Tutorial' book and need to render the 'micropost feed' at a custom location (/members) instead of at the site's root.

I've updated the SessionsController so that when a user logs in they are redirected to the new /members URL, but there are two statements needed on the member view that cause errors and prevent the page from loading with the micropost feed.

# app/views/members/index.html.erb
<%= render 'shared/micropost_form' %>
<%= render 'shared/feed' %>

The first error is:

ArgumentError in MembersController#index
First argument in form cannot contain nil or be empty

returning raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object and the second error (seen when removing the first render statement) returns undefined method 'any?' for nil:NilClass

Part of this issue is because to render the 'micropost feed' at /members the app/views/members/index.html.erb seems to need access to app/controllers/microposts_controller.rb and I'm unsure how to handle this.

Update:

micropost_controller.rb

# controllers/micropost_controller.rb

class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: :destroy

  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to '/members'
    else
      @feed_items = []
      render '/members'
    end
  end

  def destroy
    @micropost.destroy
    flash[:success] = "Micropost deleted"
    redirect_to request.referrer || '/members'
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content, :picture)
    end

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to '/members' if @micropost.nil?
    end
end

_micropost_form.html.erb

# shared/_micropost_form.html.erb

<%= form_for(@micropost, html: { multipart: true }) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost (420 chars max)..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="picture">
    <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
  </span>
<% end %>

<script type="text/javascript">
  $('#micropost_picture').bind('change', function() {
    size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
      alert('Maximum file size is 5MB. Please choose a smaller file.');
    }
  });
</script>

_feed.html.erb

# shared/_feed.html.erb

<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items %>
<% end %>

MembersController (as updated with @Mandeep's suggestion below)

class MembersController < ApplicationController
  def index
    @micropost = current_user.microposts.build
    @feed_items = current_user.microposts
  end
end
2

There are 2 answers

3
Arslan Ali On BEST ANSWER

You are not passing arguments in your partials. You need to do the following:

<%= render 'shared/micropost_form', :locals => { :micropost => @micropost }  %>
<%= render 'shared/feed', :locals => { :feed_items => @feed_items }  %>

Remember, you need to have these two variables inside your index method: @micropost and @feed_items.

0
Mandeep On

Add this code to your Controller:

class MembersController < ApplicationController
  def index
    @micropost = current_user.microposts.build
    @feed_items = current_user.microposts
  end
end