-->

How to stop NoMethodError when clicking #new & #ed

2019-09-07 06:37发布

问题:

I'm having a hard time figuring out how to incorporate multiple controller's logic into a sidebar.

For example, I want to have a section in the sidebar that uses @habits logic from the habits_controller and a section that uses @unaccomplished_goals logic from the goals_controller.

For this question let's just focus on @unaccomplished_goals.

<% @top_3_goals.each do |goal| %> shows correctly in the app's sidebar, which is derived from the goals_controller #index @top_3_goals = @unaccomplished_goals.top_3 BUT if I click on links goals/new or goals/1/edit I get the dreaded: undefined method each for nil:NilClass!

Here's a view breakdown:

I use <%= render 'sidebar/sidebar' %> in views/layouts/application.html.erb to grab views/sidebar/_sidebar.html.erb in order to use <%= render 'goals/upcoming' %> to grab views/goals/_upcoming.html.erb

views/goals/_upcoming.html.erb

<table>
  <% @top_3_goals.each do |goal| %>
    <tr>
      <td>
        <strong>
          <%= link_to goal.name, edit_goal_path(goal) %>
        </strong>
      </td>
      <td>
        <%= goal.deadline.strftime("%m-%d-%Y") %>
      </td>
    </tr>
  <% end %>
</table>

views/sidebar/_sidebar.html.erb

<div id="sidebarsection" class="panel panel-default">
<div id="sidebarheading" class="panel-heading"><h5><b>Upcoming</b></h5></div>
  <%= render 'goals/upcoming' %>
</div>

goals controller

  def index
    if params[:tag]
      @goals = Goal.tagged_with(params[:tag])
    else
      @goals = Goal.all.order("deadline")
      @accomplished_goals = current_user.goals.accomplished
      @unaccomplished_goals = current_user.goals.unaccomplished
      @top_3_goals = @unaccomplished_goals.top_3
    end
  end

goal model

class Goal < ActiveRecord::Base
	belongs_to :user
	acts_as_taggable
	scope :accomplished, -> { where(accomplished: true) }
	scope :unaccomplished, -> { where(accomplished: false) }
	validates :name, presence: true

	scope :top_3, -> do
  order("deadline DESC").
  limit(3)
end
end

Do I need to put anything in the sidebar_controller? I played around with adding logic there but it didn't seem to make any difference. I'm still a beginner so what I'm saying here may make no sense. Right now I have nothing in the sidebar_controller since the only view I have from there is _sidebar.html.erb (I'm not quite sure how partials utilize controllers). The partial _upcoming.html.erb worked perfectly if I rendered it in the goals index (the links all worked), but how can I get it to work if I render it in the _sidebar?

Thanks for putting up with me this far =]

回答1:

There shouldn't be such a thing as a sidebar controller, unless you plan to make the sidebar some sort of iframe or something ( which is strange ).

Like @patrickmcgraw suggested, I would create a before_action in the application controller to make sure that those variables are always set.

class ApplicationController < ActionController::Base
  before_action :set_top_3_goals

  def set_top_3_goals
    @top_3_goals = current_user.goals.unaccomplished.top_3
  end
end