Flynt Hamlock
Flynt Hamlock

Reputation: 359

Instance variable from Rails model: undefined method `any?'

Trying to display some affiliate products while keeping my controllers as skinny as possible. But does anybody know why this isn't working?

undefined method `any?' for nil:NilClass

app/models/shopsense.rb

require "rest_client"

module Shopsense
  def self.fetch
    response = RestClient::Request.execute(
      :method => :get,
      :url => "http://api.shopstyle.com/api/v2/products?pid=uid7849-6112293-28&fts=women&offset=0&limit=10"
    )

    # !!! ATTENTION !!!
    #
    # It works if I put the below in `shopsense` in the controller instead
    #

    @products = JSON.parse(response)["products"].map do |product|
      product = OpenStruct.new(product)
      product
    end
  end
end

app/controllers/main_controller.rb

class MainController < ApplicationController
  before_action :shopsense

  def index
  end

  def shopsense
    Shopsense.fetch
  end
end

app/views/main/index.html.erb

<% if @products.any? %>
  <% @products.each do |product| %>
    <div class="product">
      <%= link_to product.name %>
    </div>
  <% end %>
<% end %>

Upvotes: 0

Views: 195

Answers (4)

Andrey Turkin
Andrey Turkin

Reputation: 719

Because @products should be a member of MainController to be visible inside the view.

This should work:

class MainController < ApplicationController
  before_action :shopsense

  ...

  def shopsense
    @products = Shopsense.fetch
  end
end

Another option is to include the Shopsense module into MainController:

module Shopsense
  def fetch
      ...
  end
end

class MainController < ApplicationController
  include Shopsense

  before_action :fetch

  ...
end

Upvotes: 1

user2635088
user2635088

Reputation: 1618

Correct - instance variables in rails declared in the controller are available in the view. In your case, you are declaring the instance variable inside a module, and not the controller.

Try this:

def index @products = shopsense end

In this case, your controller will pass on the @products instance variable to the view

Upvotes: 1

Klaus
Klaus

Reputation: 1771

Your index.html.erb is requesting an instance variable @products, which isn't available through in the index action of your controller.

Put the instance variable in your index action:

def index
  @products = Shopsense.fetch
end

Upvotes: 1

wintermeyer
wintermeyer

Reputation: 8318

Instance variables don't belong in a model. So you can not use @products there. Put it back into the controller and you are fine.

Upvotes: 1

Related Questions