Parry
Parry

Reputation: 187

Display results of a query in a table in rails application

I have 3 models as below.

Model for Item

class Item < ApplicationRecord
    belongs_to :item_type, :class_name=>ItemType, :foreign_key=>"item_type_id"
end

and Model for Ingredients

class Ingredient < ApplicationRecord
    validates_presence_of :ingredient, :message=>"name cannot be blank!"
end

and model for recipe_ingredients

class RecipeIngredient < ApplicationRecord
  belongs_to :item, :class_name=>Item, :foreign_key=>"item_id"
  belongs_to :ingredient, :class_name=>Ingredient, :foreign_key=>"ingredient_id"
  validates_numericality_of :quantity
end

The table for ingredients has following columns

"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"ingredient" varchar, 
"inventory_unit" varchar, 
"recipe_unit" varchar, 
"created_at" datetime NOT NULL, 
"updated_at" datetime NOT NULL

The view for index of recipe ingredients is as below. The ingredients are appearing in the view. I want to pull recipe unit from ingredients table for the selected ingredient and display it in the table. I have tried it doing a query. The code is as below.

<p id="notice"><%= notice %></p>

<h1>Recipe Ingredients</h1>

<table>
  <thead>
    <tr>
      <th>Item</th>
      <th>Ingredient</th>
      <th>Quantity</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @recipe_ingredients.each do |recipe_ingredient| %>
      <tr>
        <td><%= recipe_ingredient.item %></td>
        <td><%= recipe_ingredient.ingredient.ingredient %></td>
        <td><%= recipe_ingredient.quantity %></td>
        <td><%= Ingredient.select('recipe_unit').where(:id => @ingredient_id) %></td>
        <td><%= link_to 'Show', recipe_ingredient %></td>
        <td><%= link_to 'Edit', edit_recipe_ingredient_path(recipe_ingredient) %></td>
        <td><%= link_to 'Destroy', recipe_ingredient, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Recipe Ingredient', new_recipe_ingredient_path %>

But the output I am getting is as shown in image given below.

enter image description here

Upvotes: 1

Views: 538

Answers (3)

Mark
Mark

Reputation: 10988

You can simply type the following:

recipe_ingredient.ingredient.recipe_unit

Why is this possible?

Since a RecipeIngredient belongs_to an Ingredient, you can access the Ingredient of a RecipeIngredient as if it was any other field like this:

recipe_ingredient.ingredient

Once you have the ingredient, you can pull the recipe_unit directly by typing:

recipe_ingredient.ingredient.recipe_unit

Side note:

You can omit the :class_name and :foreign_key hashes from your associativity rules in your model classes. For example, take this class:

class Student < ActiveRecord::Base
  belongs_to Course
end

By convention, rails will associate the Student class with the Course class. Rails will look for a column in the "students" database table labeled "course_id", and if "course_id" exists as a column in the table, Rails will automatically use that field as the foreign key for Student. You can use the :foreign_key => 'some_key' notation when you want to override the default conventions in rails (which isn't recommended unless its strictly necessary).

For more reading on the subject of active record migrations and foreign key associations, you can check out the rails docs.

Upvotes: 1

Sergey Moiseev
Sergey Moiseev

Reputation: 2963

First of all, you may omit :class_name and :foreign_key from your models because of convention over configuration - your models are named exactly like classes and foreign keys you list.

As for your question, you need to use yak shaving for that:

recipe_ingredient.ingredient.recipe_unit

Upvotes: 1

Taryn East
Taryn East

Reputation: 27747

Ok, it's displaying as it is because you are displaying the whole class, not an actual detail of the instance.

In this case below, you are selecting a whole set of Ingredients (the set contains only one ingredient, but it will always return a set):

Ingredient.select('recipe_unit').where(:id => @ingredient_id)

What you probably want is something like this:

Ingredient.find(@ingredient_id).recipe_unit

The differences:

  1. where always returns a set of items (even if there's just one item in the set) What is returned is not an ingredient, but an Active Relation. To just return one ingredient, you need to use find or first (or a similar such method).
  2. select just tells Rails what to pull out of the db... it doesn't tell the template what to display in the template. It says "only fetch the recipe_unit column from the db" it doesn't say and then output therecipe_unitcolumn - for that you need to actually call the recipe_unit method on the ingredient (as in the example I gave).

Note that you have the same problem with recipe_ingredient.item What column from an item do you want to display? does it have a name or a description if so - you need to actually call that eg:

<%= recipe_ingredient.item.name %>

Upvotes: 1

Related Questions