Rendering partial that belongs to another controller

1k Views Asked by At

I've got a menu controller, which is set as my root controller in routes.rb. In my menu view, i try and render the _lights.slim partial with = render :partial => 'lights/lights' but i get the following error: undefined method `lights' for nil:NilClass

MenuController:

class MenuController < ApplicationController
  def index
  end
end

Menu View (index.slim)

ul.tabs.vertical data-tab=""
  li.tab-title.active
    a href="#panel1a"  Tab 1

.tabs-content.vertical
  #panel1a.content.active
    = render :partial => 'lights/lights'

LightsController

class LightsController < ApplicationController

  before_action :discover_lights
    include LIFX
    @client = LIFX::Client.lan
    @client.discover!
    3.times do
      @client.lights.refresh
      sleep (0.5)
      puts "Found #{@client.lights.count} with labels #{@client.lights}"
    end

    def index
    end
    def new
    end

    def light_toggle
      light = @client.lights.with_label(params[:label])
      light.on? ? light.turn_off : light.turn_on
      redirect_to '/'
    end

  private
    def discover_lights
      @client = LIFX::Client.lan
      @client.discover!
    end
end

Lights View (_lights.slim)

h1.subheader LIFX Lights
table.light-table
  thead
    tr
      th Light
      th Status
      th Power On/Off
      th Brightness
  tbody
  [email protected] do |c|
    tr
      th #{c.label}
      th #{c.power}
      th =link_to 'Toggle', light_path(:label => c.label)
      th #{c.color.brightness.round(2) * 100}%
end

Routes.rb

root 'menu#index'
get '/lights', to: 'lights#index'
get '/lights/:label', to: 'lights#light_toggle', as: 'light'

I know this is a no brainer, but i'm stuck as to what to do here. I'm thinking it must be an issue with the way that when Menu#Index is called, I never knows about my LightsController, and so @client.blablabla will never make sense. But how will I make my app know about my LightsController when the view is loaded as a partial

1

There are 1 best solutions below

1
On BEST ANSWER

Partials

You must appreciate that Partials are not controller-dependent (being stored in a controllers' view directory does not tie them for use with that controller)

This means if you have the functionality to support the partial in another controller, you should be able to use it in different parts of your app

--

Error

This leads us to the identification of the problem you're receiving.

It's not the calling of the partial which causes an issue - it's how you're referring to the code inside it:

undefined method `lights' for nil:NilClass

The error is clearly that you're trying to call the lights method on an object / variable which doesn't exist. This is defined inside the partial itself here:

@client.lights.map do |c|

Therefore, you need to be able to pass the correct data to the partial, enabling it to load the @client object without being dependent on the controller

--

Fix

To do this, you may wish to consider using partial locals -

<%= render partial: "lights/lights", locals: {client: @client} %>

This means that every time you call the partial, you'll have to pass the @client object into the client local var, thus allowing the partial to run controller-independently.

Here's how you'd handle it in the partial itself:

#app/views/lights/_lights.slim
- client.lights.map do |c|