Finding an array element by id in Rails - ruby-on-rails

I am a Rails newbie (from PHP). So forgive this basic data structures question:
In the controller:
#games = Game.all
#players = Player.all
In the view:
<% #games.each do |game| %>
<%= game.player_id %>
<% end %>
When iterating over the #games, instead of displaying the player id with game.player_id, I'd like to display the player's name which can be found in the Player object (:name).
How do I 'find' the correct player record by the id stored in game.player_id?

In the controller:
#games = Game.all(:include => :player)
In the view:
<% #games.each do |game| %>
<%= game.player.name %>
<% end %>
Your data model looks odd to me. For the similar problem my data model might look like this:
class Game < ActiveRecord::Base
has_many :game_players
has_many :players, :through => :game_players
end
class GamePlayer < ActiveRecord::Base
belongs_to :game
belongs_to :player
end
class Player < ActiveRecord::Base
has_many :game_players
has_many :games, :through => :game_players
end
Now in the controller I would query the games:
#games = Game.all(:include => :players)
In the view:
<%#games.each do |game| %>
<% games.players.each do |player| %>
<%= player.name %>
<%end%>
<%end%>
Edit 1
If you have a concept of team then, I will introduce the team model:
class Player < ActiveRecord::Base
has_many :team_players
has_many :teams, :through => :team_players
end
class TeamPlayer < ActiveRecord::Base
belongs_to :player
belongs_to :team
end
class Team < ActiveRecord::Base
has_many :team_players
has_many :players, :through => :team_players
belongs_to :game
# attributes name, score team size constraints etc.
end
class Game
has_many :teams
has_many :players, :through => :teams.
end
Adding a new game:
#game = Game.new
#team_a = #game.teams.build(:name => "Foo")
#team_a.players << Player.find_all_by_name(["John", "Grace"])
#team_b = #game.teams.build((:name => "Bar")
#team_b.players << Player.find_all_by_name(["Kelly", "Yuvan"])
#game.save
While querying games in your controller:
#games = Game.all(:include => [{:teams => :players}])
In your view:
<%#games.each do |game| %>
<% games.teams.each do |team| %>
<% team.players.each do |team| %>
<%= player.name %>
<%end%>
<%end%>
<%end%>

Related

Cannot access attributes from associated model rails

I have three models, ingredient, recipe_ingredient and recipy
class Ingredient < ApplicationRecord
has_many :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipy, :dependent => :destroy
belongs_to :ingredient
end
class Recipy < ApplicationRecord
has_many :recipy_steps
has_many :recipe_ingredients, :dependent => :delete_all
end
I am trying to access the ing_name attribute in the ingredients table from recipies show page.
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %>
<%= ing.ingredient.ing_name %>
</p>
def Show from the recipies controller:
def show
#recipe_ingredients = #recipy.recipe_ingredients
end
But I keep receiving the following error msg:
undefined method `ing_name' for nil:NilClass
My ingredient_params:
def ingredient_params
params.require(:ingredient).permit(:ing_name)
end
It does seem to work like this:
<%= Ingredient.where(id: ing.ingredient_id).pluck(:ing_name) %>
But this does not use the connection between the tables if I understand correctly? Any help? Thanks.
You have ingredient nil thats why you got the error.
Must be your controller has some before_action hook to load recipy
class RecipesController < ApplicationController
before_action :load_recipy, only: :show
def show
#recipe_ingredients = #recipy.recipe_ingredients
end
private
def load_recipy
#recipy = Recipy.find(params[:id])
end
end
You can try this to avoid this nil error(undefined method 'ing_name' for nil:NilClass)
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %>
<%= ing.try(:ingredient).try(:ing_name) %>
</p>
From Rails 5 by default you got one required option to make ingredient always not nullable
like below
belongs_to :ingredient, required: true
It will also prevent this error of
class RecipeIngredient < ApplicationRecord
belongs_to :recipy, :dependent => :destroy
belongs_to :ingredient, required: true
end
the problem is because inside your show method #recipy is nil,
here is usually code for show
controller
def show
#recipy = Recipy.find(params[:id]) # --> you missed this line
#recipe_ingredients = #recipy.recipe_ingredients # #recipy will be null without line above
end
view
<% #recipe_ingredients.each do |ing| %>
<p> <%= ing.amount %> <%= ing.unit %> <%= ing.ingredient.ing_name %> </p>
<% end %>
I would like also add some suggestion to your model relationship as follow since Ingredient and Recipy shows many to many relationship
class Ingredient < ApplicationRecord
# -> recipe_ingredients -> recipies
has_many :recipe_ingredients, :dependent => :destroy
has_many :recipies, through: :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipy
belongs_to :ingredient
end
class Recipy < ApplicationRecord
has_many :recipy_steps
# -> recipe_ingredients -> ingredients
has_many :recipe_ingredients, :dependent => :destroy
has_many :ingredients, through: :recipe_ingredients
end

I want to get the data from many to many table

I want to get the data from many to many relationship table (Tag-Service-Category) like this below in tag/show.html.erb.
class Tag < ActiveRecord::Base
has_many :service_tags
has_many :services, through: :service_tags
end
class ServiceTag < ActiveRecord::Base
belongs_to :service
belongs_to :tag
end
class Service < ActiveRecord::Base
has_many :service_tags
has_many :tags, through: :service_tags
has_many :service_categories
has_many :categories, through: :service_categories
end
class ServiceCategory < ActiveRecord::Base
belongs_to :service
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :service_categories
has_many :services, through: :service_categories
end
I wrote the code like this, but it`s not working.
#tag = Tag.find(params[:id])
<% #tag.services.each do |service| %>
<% service.categories.each do |category| %>
<span class="category" class="<%= category.id %>"><%= category.name %></span>
<% end %>
<% end %>
controllers/tags_controller.rb
class TagsController < ApplicationController
def show
#tag = Tag.find(params[:id])
#tags = Tag.all
end
end
Although you have the db relationships correct, you'll still need to call out the connecting model. Because you're doing a double many to many relationship you'll need to create an in-between array. Try adding this to your view:
<% services_array = [] %>
<% #tag.service_tags each do |service_tag| %>
<% services_array << service_tag.service %>
<% end %>
<% services_array.each do |service| %>
<span class="category">
<%= service.service_category.category.id %>
<%= service.service_category.category.name %>
</span>
<% end %>

Join Query on 2 tables(Rails 4)

I having the following in my show.html.erb:
<% if #doctor.referrals_as_from.count > 0 %>
<% #doctor.referrals_as_from.each do |referral| %>
<%= referral.to_id %>
<% end %>
<% end %>
This works fine, giving me a list of matching id numbers from my referral model.
But, rather than getting a list of id numbers I would like to cross reference the "full_name" column from the Doctors model by using the identified id in referrals,basically an inner join. What is the most elegant way of doing this? Add a new method to the controller and to do a joins or includes, or is there a simpler way?
Models:
doctor.rb
class Doctor < ActiveRecord::Base
self.primary_key = "npi"
has_many :referrals_as_from, :class_name => 'Referral', :foreign_key => 'from_id'
has_many :referrals_as_to, :class_name => 'Referral', :foreign_key => 'to_id'
end
referral.rb
class Referral < ActiveRecord::Base
belongs_to :doctor
end
Use this.
<% if #doctor.referrals_as_from.count > 0 %>
<% #doctor.referrals_as_from.each do |referral| %>
<%= referral.doctor.full_name %>
<% end %>
<% end %>
The Referral model actually has two doctors associated with it, as defined by to_id and from_id. So you might need to do the following:
referral.rb
class Referral < ActiveRecord::Base
belongs_to :to_doctor, :class_name => "Doctor", :primary_key => "to_id", :foreign_key => "npi"
belongs_to :from_doctor, :class_name => "Doctor", :primary_key => "from_id", :foreign_key => "npi
end
Then the code becomes
referral.to_doctor.full_name

Polymorphic Nested Form

I'm having issue creating a nested polymorphic form. I am following the solution from this problem:
Rails: has_many through with polymorphic association - will this work?
The description was: A Person can have many Events and each Event can have one polymorphic Eventable record
Here are the relevant models:
class Event < ActiveRecord::Base
belongs_to :person
belongs_to :eventable, :polymorphic => true
end
class Meal < ActiveRecord::Base
has_one :event, :as => eventable
end
class Workout < ActiveRecord::Base
has_one :event, :as => eventable
end
class Person < ActiveRecord::Base
has_many :events
has_many :meals, :through => :events, :source => :eventable,
:source_type => "Meal"
has_many :workouts, :through => :events, :source => :eventable,
:source_type => "Workout"
end
My controller looks like this:
def
#person = Person.new
#person.meals.new
#person.workouts.new
new
My view looks like this:
<%= form_for #person do |person| %>
<%= person.fields_for :meals, #person.meals.build do |meals| %>
<%= meals.text_field :food %>
<% end %>
<% end %>
The error I am currently getting is:
unknown attribute: person_id
I would think that the polymorphic association is hindering the creation of the object because meals can't be create until person has been created? Did I set up the form correctly? Thanks!
You'll need to include a person_id attribute in the events table (as per the belongs_to association)
There are also some other issues you should resolve:
Controller
def new
#person = Person.build
end
def create
#person = Person.new(person_attributes)
#person.save
end
private
def person_attributes
params.require(:person).permit(:your, :attributes, events_attributes: [:eventable_type, :eventable_id, meal_attributes: [:params], workout_attributes: [:params]])
end
Models
#app/models/person.rb
Class Person < ActiveRecord::Base
has_many :events
has_many :meals, :through => :events, :source => :eventable,
:source_type => "Meal"
has_many :workouts, :through => :events, :source => :eventable,
:source_type => "Workout"
def self.build
person = Person.new
person.events.build.build_meal
person.events.build.build_workout
end
end
Views
#app/views/people/new.html.erb
<%= form_for #person do |person| %>
<%= person.fields_for :events do |e| %>
<%= e.fields_for :meal %>
<%= e.text_field :food %>
<% end %>
<% end %>
<% end %>

Rails: Create form for #score while in different model no direct associations

I want to create a multiple form for editing scores from a different model.
The main model is a Formrule model that consists of a habtm association with a Scoretype model
and has a habtm association with a Room model.
Both models are used to query a Scores model resulting in a #scores instance. It is for this instance I want to create a form, but the problem is that no field_for are being created. I know that the #scores is populated correctly, but the form does not show up.
This is the form as I have it now
<%= form_tag '/scores/update_scores' do %>
<table>
<tr>...</tr>
<% for score in #scores %>
<% fields_for :scores, score do |score| %>
<tr>
<td>
<%= score.hidden_field(:form_id) %>
<%= score.hidden_field(:team_id) %>
<%= score.hidden_field(:scoretype_id) %>
</td>
<td>
<%= score.number_field :scorevalue %>
</td>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag 'Update' %>
<% end %>
And these are the Models:
Formrule
class Formrule < ActiveRecord::Base
belongs_to :form
has_and_belongs_to_many :scoretypes
has_and_belongs_to_many :rooms
has_many :teams, :through => :rooms
end
Scoretype
class Scoretype < ActiveRecord::Base
has_many :scores
has_and_belongs_to_many :formrules
end
Room
class Room < ActiveRecord::Base
has_many :teams
has_and_belongs_to_many :formrules
end
Team
class Team < ActiveRecord::Base
has_many :scores
belongs_to :room
belongs_to :group
end
Score
class Score < ActiveRecord::Base
belongs_to :form
belongs_to :team
belongs_to :scoretype
validates_uniqueness_of :id, :scope => [:team, :scoretype]
end
And finally, the used controller (Formrule)
def show
#formrule = Formrule.find(params[:id])
#scoretypes = #formrule.scoretypes.all.collect
#rooms = #formrule.rooms.all.collect
#teams = Team.find(:all, :conditions => {:room_id => #rooms})
#scores = Score.order("team_id").all(:conditions => {:scoretype_id => #scoretypes, :team_id => #teams})
...
end
Why is the form not showing up? any suggestions?
Thank you all in advance!
Try using <%= fields_for ... %> instead of <% fields_for ...%>.

Resources