0

I have two models, Subject and Course. A Course belongs_to a Subject and a Subject has_many Courses. When creating a new course, I am using collection_select to get all subjects in the database so I can select the Subject which the course belongs to. This is working fine, however im having a problem getting subject.name from displaying in the course index.html page, and instead I can only get its id to appear. I have tried doing <%= course.subject.name %> which gives me an error: undefined method `name' for nil:NilClass. What should I do in order to display the subject.name in the course view page?

Here is my code:

course _form:

  <div class="field">
    <%= f.label "Subject" %>
    <%= collection_select :course, :subject_id, Subject.all, :id, :name %>
  </div>

index.html:

<div class="courses">
  <div class="semesters">
    <h3>Courses</h3>
    <% @grade.courses.each do |course| %>
    <div class="course_group">
      <div class="course_list">
        <h3><%= course.subject.name %></h3>
        <p><%= course.title %></p>
        <%= link_to "View Course", [@grade, course], :class => "button button_orange" %>
        <div class="course_links">
        <% if can? :update, @course %>
          <%= link_to 'Edit', edit_grade_course_path(@grade, course) %> |
        <% end %>
        <% if can? :destroy, @course %>
          <%= link_to 'Destroy', [@grade, course], method: :delete, data: { confirm: 'Are you sure?' } %>
        <% end %>
        </div>
      </div>
      </div>
    <% end %>
  </div>
  <div class="create_course">
    <% if can? :create, @course %>
    <%= link_to 'Add New Course', new_grade_course_path(@grade, @course), :class => "button button_orange" %>
    <% end %>
  </div>
</div>

courses_controller.rb:

class CoursesController < ApplicationController
  before_action :set_course, only: [:show, :edit, :update, :destroy]
  before_action :set_grade
  load_and_authorize_resource
  respond_to :html

  def index
   @grade = Grade.find(params[:grade_id])
   @subjects = Subject.all
   @courses = @grade.courses.all
   # respond_with(@course)
  end
.
.
.
  def course_params
      params.require(:course).permit(:title, :period, :description, :semester, :grade, :grade_id, :video_url, :chapter_id, :subject_id)
  end
end

course.rb :

class Course < ActiveRecord::Base
    # TODO: add validations
    resourcify
    belongs_to :grade
    has_many :chapters
    has_many :packages
    belongs_to :subject
end

subject.rb:

class Subject < ActiveRecord::Base
    has_many :courses
end

2 Answers2

1

try this code

<%= course.subject.name if course.subject and course.subject.name %>

As we are working on relational database, while fetching data from relationship we firstly need to check relation with that table is exists or not, also need to check field in that relational table is not nil/blank. You can also use try method for this.

Checkout below link

http://www.rubydoc.info/docs/rails/Object%3Atry

chaitanya
  • 1,974
  • 3
  • 17
  • 35
1

I'd say to go for validations than to check for each column's existence; it's simply redundant.

class Subject < ActiveRecord::Base
  validates :name, presence: true
end

This way, a subject can't be saved in the database until it has a name, and then in your view you do not need to check for the existence of name field.

Or if you would like to go for existence check, Rails provides a way for it as well. Here's how:

course.try(:subject).try(:name) # this code won't crash even if the `name` or `subject` is `nil`.
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76