Search code examples
ruby-on-railsinstagraminstagram-api

NoMethodError when implementing Instagram Gem for Ruby on Rails website


I have just completed One Month Rails tutorial and this is the website I've build: https://warwicktri.herokuapp.com/. Now I'm trying to pull an Instagram feed onto the home page but I get the NoMethodError in Pins#index on my localhost.

undefined method `each' for nil:NilClass

<div>
  <% @instagram.each do |instagram| %>
    <%= image_tag instagram.images.first.last.url %>
  <% end %>
</div>

I think that it means that @instagram is not declared properly but I do not know where did I go wrong.

This is the code in my pins_controller.rb:

def index
  @pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 5)
  respond_with(@pins)
  @instagram = Instagram.user_recent_media("264208635")
  respond_with(@instagram)
end

I also tried putting @instagram in another controller by itself instead, but I still get the same error:

class InstagramController < ApplicationController
  def index
    @instagram = Instagram.user_recent_media("264208635")
    respond_with(@instagram)
  end
end

How should I declare @instagram in my code?

Update 1: My code for view (index.html.erb):

<div id="pins" class="transitions-enabled">
  <% @pins.each do |pin| %>
    <div class="box panel panel-default">
      <%= link_to image_tag(pin.image.url(:medium)), pin %>
      <div class="panel-body">
        <p><%= pin.description %></p>
        <p><strong><%= pin.user.name if pin.user %></strong></p>
        <% if pin.user == current_user %>
          <div class="actions">
            <%= link_to edit_pin_path(pin) do %>
              <span class="glyphicon glyphicon-edit" aria-hidden="true"></span> Edit
            <% end %>
            <%= link_to pin, method: :delete, data: { confirm: 'Are you sure?' } do %>
              <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
            <% end %>
          </div>
        <% end %>  
      </div>
    </div>
  <% end %>
</div>

<div class="center">
  <%= will_paginate @posts, renderer: BootstrapPagination::Rails %>
</div>

<div>
    <% @instagram.each do |instagram| %>
      <%= image_tag instagram.images.first.last.url %>
    <% end %>
</div>

Solution

  • After some help from my friend, I realised where I went wrong and how to correct the NoMethodError.

    There's 2 parts to this answer:
    1) Adding the Instagram code into the pins controllers
    2) Using a separate controller for Instagram data

    Note that this answer is specifically for the One Month Rails tutorial and may or may not be applicable directly to every web application.

    1) Adding the Instagram code into the pins controllers

    • Mattan Griffel was right about the respond_with(@pins) part. respond_with(@pins) caused my controller action to skip the rest of the part. So when I changed the order of the code, it worked.
    • I most likely made another mistake when I tried to remove it after Mattan suggested it so it didn't work then (see comments above).

    Part of my pins_controller.rb:

      def index
        @instagram = Instagram.user_recent_media("264208635")
        @pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 5)
        respond_with(@pins)
      end
    

    2) Using a separate controller for Instagram data

    • I got the same NoMethodError even when I used a separate controller because while I declared @instagram in my instagram_controller.rb, I was trying to render the data into my pins view (views/pins/index.html.erb). However, I did not declare @instagram in my pins_controller.rb.
    • So I copied @instagram = Instagram.user_recent_media("264208635") from instagram_controller.rb and pasted it into my pins_controller.rb under the index method; like this:

    Part of my pins_controller.rb:

      def index
        @instagram = Instagram.user_recent_media("264208635")
        @pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 5)
        respond_with(@pins)
      end
    

    Similarly, respond_with(@pins) causes my controller action to skip the rest of the part, so @instagram = Instagram.user_recent_media("264208635") has to be added before respond_with(@pins) and not after. Then, it worked.