Reputation: 15
rails newbie here. I want my questions/view/index to show the name of the language associated with a question, rather than the language_id.
My question model is:
class Question < ActiveRecord::Base
validates :phrase, presence: true
has_many :answers, dependent: :delete_all
belongs_to :language
end
class CreateQuestions < ActiveRecord::Migration
def change
create_table :questions do |t|
t.string :phrase
t.string :language
t.timestamps
end
end
end
class AddLanguageIdToQuestions < ActiveRecord::Migration
def change
add_column :questions, :language_id, :integer
end
end
My language model is:
class Language < ActiveRecord::Base
end
class CreateLanguages < ActiveRecord::Migration
def change
create_table :languages do |t|
t.string :name
t.timestamps
end
end
end
In my questions controller:
def index
@questions = Question.all
@language = Language.find(@questions.language_id)
end
In the questions/_form.html.erb:
<p>
<%= f.label :language_id %><br>
<%= f.select :language_id, @languages.map { |l| [l.name, l.id] }, {:prompt => 'select language'} %>
</p>
And in the questions/view/index.html.erb:
<% @questions.each do |question| %>
<li>"<%= link_to question.phrase, question %>" in <%= question.language.name %>?%></li>
<% end %>
The error I keep getting, despite trying several variations of "question.language.name" (which works just fine in the show view) is "undefined method "language_id" in the index view.
Any help would be very much appreciated.
Upvotes: 0
Views: 2321
Reputation: 3721
just change your index action to:
def index
@questions = Question.all.includes(:language)
end
edit
<% @questions.each do |question| %>
<% unless question.language.nil? %>
<li>"<%= link_to question.phrase, question %>" in <%= question.language.name %>?%></li> <% end %>
<% end %>
OR
<% @questions.each do |question| %>
<li>"<%= link_to question.phrase, question %>" in <%= question.language.name unless question.language.nil? %>?%></li>
<% end %>
Both will work fine depends on you what do you want.
feel free to ask if problem continues or not solved.
Your Problem
What you were doing wrong was:
finding all questions and then this line was wrong finding all question's language at once.
@language = Language.find(@questions.language_id)
And to avoid this: better solution is to avoid N + 1 query problem using includes
Upvotes: 1
Reputation: 1936
@questions.language_id
is incorrect because you are trying to retrieve a single id from an array. i.e. Question.all
returns an array. Also, Language.find
requires a single id parameter to return a single language.
What exactly are you trying to return with Language.find(@questions.language_id)
? An array of languages that have a question that belong to it?
Also, where is the _form.html.erb partial called? By default, rails scaffold will call the partial in the new and edit actions and therefore if you are trying to set @languages
for the select field in the form partial, then you would not do it in the index action. Also, Consider using a collection select for this field as it is for an association.
Upvotes: 0
Reputation: 76774
This sounds like a job for ActiveRecord Associations, specifically the has_many
association:
ActiveRecord associations basically use a foreign_key
in your database to pull relational data & append to your object. Currently, you're only focused on using a single object, without any associated data.
--
Your problem can be fixed using the following:
#app/models/question.rb
Class Question < ActiveRecord::Base
belongs_to :language
end
#app/models/language.rb
Class Language < ActiveRecord::Base
has_many :questions
end
This will allow you to call the following in your controller & view:
#app/controllers/questions_controller.rb
Class QuestionsController < ApplicationController
def index
@questions = Question.all
end
end
#app/views/questions/index.html.erb
<% @questions.each do |question| %>
<%= question.language.name %>
<% end %>
--
Bonus
You can use the .delegate
method to provide you with the ability to stop the law of dementer
issue:
#app/models/question.rb
Class Question < ActiveRecord::Base
belongs_to :language
delegate :name, to: :language, prefix: true #-> @question.language_name
end
Upvotes: 1