cratag
cratag

Reputation: 122

Is there a way to use Rails Scaffold data in a different view?

I have generated a Scaffold in rails which has some information about some plants: name, description. id.

I want to show that information in my root "home#index"

but the index page doesn't render and I get the error:

NoMethodError in Home#index

undefined method `each' for nil:NilClass

<% @plants.each do |plant| %>

this is my code

I know it's not "importing" my @plants class, so how can I get it imported into different views?

<table class="table">
  <tbody>
    <% @plants.each do |plant| %>
      <tr>
        <td><%= plant.plant_name %></td>
        <td><%= plant.plant_description %></td>
        <td><%= plant.plant_id %></td>
      </tr>
    <% end %>
  </tbody>
</table>

Upvotes: 0

Views: 126

Answers (1)

max
max

Reputation: 102250

You have got the concepts all wrong here. The Rails scaffold command sets up a model, controller and views. The scaffolding command does not set up any data. You would setup data by using the rails db:seed command. @plants is not a class - its just an instance variable that the scaffold will assign to Plant.all.

In Ruby you can reference an instance variable even if it has not been defined and simply get nil. But when you call @plants.each do |plant| you get an error since you're calling #each on nil. This one the key gotchas in Ruby which tends to trip up both beginners and sometimes even experienced developers.

In Rails each request is matched by the router to a controller and action (a method on the controller). If you want to display a list of the plants on your HomeController you need to assign that instance variable:

class HomeController < ApplicationController
  def index
    @plants = Plant.all
  end
end

Rails then "provides" all the instance variables of the controller to the view - this is known as the view context.

If you want to share code between your HomeController and PlantController you would use a module:

module Planted
  extend ActiveSupport::Concern

  included do
    before_action :set_plants, only: [:index]
  end

  def set_plants
    @plants = Plant.all
  end
end

class PlantsController < ApplicationController
  include Planted
  # ...
end

class HomeController < ApplicationController
  include Planted
  # ...
end

Or inheritance if it passes the liskov substitutability principle.

If you want to share view code use partials.

Upvotes: 1

Related Questions