how to render this partial in rails - ruby-on-rails

i am trying to render this partial of the association belongs_to and has_many i.e
my model is as thus
activity Model
class Activity < ActiveRecord::Base
has_many :talks
end
talk model
class Talk < ActiveRecord::Base
belongs :activity
end
in my talk controller i have
#activities = Activity.where(user_id: [current_user.friend_ids, current_user])
#talks = Talk.find(:all, :order => "created_at DESC")
and in view i have
<% activity.talks.each do |c| %>
<div class="media">
<a class="pull-left" href="#">
<%= image_tag(c.user.image.url(:tiny),:style=> "width: 100%;")%>
</a>
<div class="media-body">
<strong><%= c.user.username %></strong> <%= c.details %><br>
<small><span class="muted"><%="#{time_ago_in_words(c.created_at)} ago "%></span></small>
</div>
</div>
<% end %>
this displays all the talk for each activity
how do i create a partial of <% activity.talks.each do |c| %>

Create a partial in
app/views/talks/_talk.html.erb
and call
<%= render activity.talks %>
This will render one _talk.html.erb partial for each talk in the activity.talks collection, which will have access to a talk variable.
Furthermore, you can optimize the code by preventing N + 1 queries. In your controller,
#activities = Activity.includes(:talks).where(user_id: [current_user.friend_ids, current_user])
Notice the includes(:talks). Read more about eager loading in the docs linked above.

Related

How to pass more than one parameters to render in rails?

Below is my review.html.erb:
<% provide(:title, 'All reviews') %>
<h1>All reviews</h1>
<ol class="reviews">
<%= render #reviews %>
</ol>
<%= will_paginate #reviews %>
And my _review.html.erb looks like:
<li>
<p>Student: <%= Student.find(review.student_id).name%></p>
<p>Score: <%= review.score%></p>
<p>Review: <%= review.review%></p>
<p>Created at: <%= review.created_at%></p>
</li>
How can I pass #students as well to render for example?
I tried <%= render #reviews, #students %> in review.html.erb and Student: <%= student.name%> in _review.html.erb. It didn't work.
You don't actually need to pass multiple parameters. You just need to setup the assocations between reviews and students:
class Student < ApplicationRecord
has_many :reviews
end
class Review < ApplicationRecord
belongs_to :student
# optional but avoids a law of demeter violation
delegate :name, to: :student, prefix: true
end
<li>
<p>Student: <%= review.student_name %></p>
<p>Score: <%= review.score %></p>
<p>Review: <%= review.review %></p>
<p>Created at: <%= review.created_at %></p>
</li>
To avoid a N+1 query issue you should use includes or eager_load to load the student with the reviews:
#reviews = Review.includes(:student)
.all
If you do actually want to pass additional arguments when rendering a collection (which isn't needed here) you do it with local assigns:
<%= render #reviews, locals: { foo: 'bar' } %>
This will be available in the partial as foo or local_assigns(:foo).
Reivew table and students are related
In _review.html.erb , you don't need use Student.find(review.student_id)
<li>
<p>Student: <%= review.student&.name%></p> // changed
....
</li>

Narrow elements in a join table by a dropdown menu. (Rails 4)

for one of my join tables, I'd like to filter results based on a dropdown menu selection. Before I explain further, I will provide the relevant code.
I have 3 models in question:
class Scoreboard
has_many :teams, has_many :team_matches
end
class Team
belongs_to Scoreboard
#self reference with the teams to create team_matches.
has_many :first_team, class_name: "TeamMatch", foreign_key: "team_a_id", dependent: :destroy
has_many :team_a, through: :first_team, source: :team_a
has_many :second_team, class_name: "TeamMatch", foreign_key: "team_b_id", dependent: :destroy
has_many :team_b, through: :second_teams, source: :team_b
end
And the final Model which is a join table of teams:
class Team_Match
belongs_to :team_a, class_name: "Team"
belongs_to :team_b, class_name: "Team"
belongs_to :scoreboard
end
Team Matches Controller Code for the Index View:
class TeamMatchesController < ApplicationController
require 'will_paginate/array'
def index
#selected = true
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#teams = #scoreboard.teams
#matches = #scoreboard.team_matches.order("match_date DESC").paginate(page: params[:page], per_page: 5)
end
end
The Index Page View:
<h2 class="team-matches-header">TEAM MATCHES</h2>
<% if manager_or_owner?(#scoreboard, current_user) %>
<%= link_to "Add Matches", new_scoreboard_team_match_path(#scoreboard), class: "btn btn-primary" %>
<%= link_to "Clear Matches", deletematches_scoreboard_path(#scoreboard),method: :delete, class: "btn btn-danger", :data => {:confirm => "Are you absolutely sure you want to delete all matches?"} %>
<% end %>
<%= form_tag(scoreboard_team_matches_path, :method => "get", id: "match-search-form", autocomplete: "off") do %>
<div class="row new-member-field">
<div class="col-xs-12 col-sm-6">
<%= select_tag "teams", options_from_collection_for_select(#teams, "id", "name"), prompt: "Select something", class:"form-control" %>
<%= submit_tag 'Filter' %>
</div>
</div>
<% end %>
<div class="match-list">
<%= render 'match_list' %>
</div>
The Match List Partial
<% if #matches.present? %>
<% #matches.each do |game| %>
<div class="row match-div clearfix" id="match_<%= game.id %>">
<div class="col-xs-12 match-column">
<div class="facing-teams">
<div class="first-team">
<%= game.team_a.name %>
</div>
<div class="second-team">
<%= game.team_b.name %>
</div>
</div>
</div>
</div>
<% end %>
<% end %>
<div class="row">
<div class="col-xs-12 new-member-pages">
<%= will_paginate #matches %>
</div>
</div>
So far on the team matches index page, I have been able to put a dropdown menu selection with a list of teams. The trouble I'm having is how to make it functional. Upon submission of a team from the dropdown selection, I would like to display a list of Match objects(#matches) whose :team_a_id or :team_b_id matches the selected Team's id. How would I go about doing that?
I would use scopes to achieve what you want. Scopes are reusable filters that you can apply to an association to find exactly the records that you want.
This is how you would create a scope that finds the matches for a particular team:
class Team_Match
scope :has_team, ->(team_id) {
team_a = arel_table[:team_a_id].eq(team_id)
team_b = arel_table[:team_b_id].eq(team_id)
team_a_or_b = team_a.or(team_b)
where(team_a_or_b)
}
end
This uses arel (which ActiveRecord uses under the hood to create SQL queries) in order to find a match in either the team_a_id or team_b_id columns. If you have no idea what's going on with the above code, take a quick trip to Mastering AR and Arel to get up to speed.
You use the scope like this:
matches = Team_Match.has_team(team_id)
You can also use the scope on any relationship that joins to Team_Match:
matches = #scoreboard.team_matches.has_team(team_id)
Scopes can also be chained together:
matches = #scoreboard.team_matches.has_team(team_id).where(match_date: today)
The scope allows you to pass in the team id from the select box to find the matches:
def index
#selected = true
#scoreboard = Scoreboard.find(params[:scoreboard_id])
#teams = #scoreboard.teams
#matches = #scoreboard.team_matches.order("match_date DESC")
#matches = #matches.paginate(page: params[:page], per_page: 5)
# we apply the scope (if present) to only show the matches for the selected team
if (team_id = params[:selected_team_id])
#matches = #matches.has_team(team_id)
end
end
The only change you would need to make to the above code is working out what the actual name is of the param variable that holds the selected team id.

Can't Get Photos to Work in Rails

I am having all kinds of trouble doing a simple task, displaying a photo as part of a result set for each one. I'm pretty new to Rails in general, coming from another language where I can do this in seconds.
The #photo query finds 0 records even though multiple records for photos are in the DB matching the property ID.
I'm not too sure what I'm doing wrong here.
Here are my relevant files:
app/controllers/properties_controller.rb:
class PropertiesController < ApplicationController
......
def all
# gets all of the properties and uses will_paginate
#properties = Property.paginate(page: params[:page])
# should get the first positioned photo matching the results in the #properties query
#photos = Photo.where(:property_id => #properties.map(&:id)).order("position").first
end
# ......
end
app/models/property.rb:
class Property < ActiveRecord::Base
belongs_to :listing_type
belongs_to :property_type
belongs_to :status
has_many :photos
# ......
end
app/models/photo.rb:
class Photo < ActiveRecord::Base
mount_uploader :photoname, PhotoUploader
belongs_to :property
acts_as_list scope: :property_id
validates :photoname, presence: true
validates :property_id, presence: true
end
details.html.erb:
<% #properties.reverse_each do |property| %>
<div class="item col-md-4">
<div class="image">
<%= link_to property_path(property) do %>
<span class="btn btn-default"><i class="fa fa-file-o"></i> Details</span>
<% end %>
<%= image_tag(property) %>
</div>
# ......
<% end %>
Since you have a has_many realtion in the Property, you have to just access to the relation of the property to read all teh photoes:
photo = #property.photos.order("position").first
Well if you need to grab all the photoes of properties, use include to properties grab:
#properties = Property.includes(:photos).paginate(page: params[:page]).reverse
the include is needed to avoid N + 1 problem, then try replacing it with a first photo:
#photos = #properties.map { |pr| pr.photos.order("position").first }
Mpve reverse to controller, and to use #photos along with #properties use index:
<% #properties.each.with_index do |property, i| %>
#...
<%= image_tag(#photos[i]) %>
<- end >
NOTE that the code selecting an image pr.photos... be better moved to a decorator (see gem draper).
After a TON of help from #МалъСкрылевъ, which also had me learning a few new ways of "thinking" this in general, his answer led me to rethink what I was doing and go back to simply starting over and reconstructing what ended up being VERY basic. All I needed to do was make the photo query for the first photo in my loop over the properties. DUH! Here's what I did in case it helps some other poor new Rails developer!
properties_controller.rb
class PropertiesController < ApplicationController
......
def all
# gets all of the properties and uses will_paginate
#properties = Property.paginate(page: params[:page])
......
end
details.html.erb
<% #properties.each do |property| %>
<div class="item col-md-4">
<% #photo = Photo.where(property_id: property.id).order("position").first %>
<div class="image">
<%= link_to property_path(property) do %>
<span class="btn btn-default"><i class="fa fa-file-o"></i> Details</span>
<% end %>
<%= image_tag(#photo.photoname.medium) %>
</div>
......

Rails link_to an .each join

I have this code which associates one table to another. Using Set it collects all data and only shows it once if there are other similar values.
genre_names = Set.new
<% #pm_relationships = PmRelationship.where(:people_id => #person.id) %>
<% #pm_relationships.each do |pm_relationship| %>
<% #movie=Movie.find(pm_relationship.movie_id) %>
<% #mg_relationships = MgRelationship.where(:movie_id => #movie.id) %>
<% #mg_relationships.each do |mg_relationship| %>
<% #genre=Genre.find(mg_relationship.genre_id) %>
<% genre_names.add(#genre.name) %>
<% end %>
<% end%>
# actual view code
<ul class="basic-info-genres">
<%= "<li>#{genre_names.to_a.join('</li><li>')}</li>".html_safe %>
</ul>
My problem here is how a link_to would work in the print code provided
<%= "<a><li><button><span>#{genre_names.to_a.join('</span></button></li></a><a><li><‌​‌​button><span>')}</span></button></li></a>".html_safe %>
How to make the above print to have this link to /genres/<%=#genre.id%>?
I've tried
<%= "<a href='/genres/#{#genre.id}'><li><button><span>#{genre_names.to_a.join('</span></‌​‌​button></li></a><a><li><button><span>')}</span></button></li></a>".html_safe %>
but this only links to the first genre shown
Any ideas?
Thanks
Add to genres the whole #genres, not only the #genre-name, then you can use the each-loop in the view code.
For the Controller (you should have your programmic logic there):
#genres = Set.new
#pm_relationships = PmRelationship.where(:people_id => #person.id)
#pm_relationships.each do |pm_relationship|
movie=Movie.find(pm_relationship.movie_id)
#mg_relationships = MgRelationship.where(:movie_id => movie.id)
#mg_relationships.each do |mg_relationship| %>
genre=Genre.find(mg_relationship.genre_id) %>
#genres.add(genre) %>
end
end
For the view:
<ul class="basic-info-genres">
<% #genres.each do |genre| %>
<li><%= link_to genre.genre_name, "#{root_url}genres/#{genre.id}" %></li>
<% end %>
</ul>
If I understand correctly, you want to link all genres that are associated with a movie.
To do this, in your controller, load the genres for a user's movies. With the correct association setup, this is as easy as #person.genres. So let's do that.
class Person < ActiveRecord::Base
has_many :pm_relationships
has_many :movies, through: :pm_relationships
has_many :genres, through: :movies
end
class PmRelationship < ActiveRecord::Base
belongs_to :person
belongs_to :movie
end
class Movie < ActiveRecord::Base
has_many :mg_relationships
has_many :genres, through: :mg_relationships
end
With that setup, in your controller, just setup an instance variable to list all genres for #person
#genres = #person.genres
Then in your view, use the block form of link_to so it's easier to code your html
<ul class="basic-info-genres">
<% #genres.each do |genre| %>
<%= link_to genre do %>
<li>
<button>
<span><%= genre.name %>‌</span>
</button>
</li>
<% end %>
<% end %>
</ul>
Basically, you can't have any direct child element instead of li within ul. You will need to have <a> within li, however, we can apply css to <a> so that it looks like whole 'li' have the clickable link.
From your actual code, update the snippet.
<ul class="basic-info-genres">
<% genre_names.each do |genre_name| %>
<li>
<%= link_to genre_name, genre_path(#genre), :class => 'clickable-li' %>
</li>
<% end %>
</ul>
You need to set your <a> to display: block;
# css file
.clickable-li {
display: block;
}

How to correctly call models in controller

My Chefs Model is linked to my Meals Model through chef_id. I am displaying information about the chef, and would also like to show information about his meals. I have not been able to figure out the correct way to call it in the controller. Any ideas?
chef controller:
def index
#chefs=Chef.paginate(page: params[:page])
#meals = ????? Cant figure out how to call this
end
Index.html.erb
<div class = 'chef'>
<div class = 'row'>
<% #chefs.each do |chef| %>
<%= render chef %>
<% end %>
</div>
</div>
<%= will_paginate %>
_chef partial
<div class = 'span4'>
<div class = 'chef-box'>
<h2><center><%= link_to chef.name, chef %></center></h2>
<h2><center>"<%= chef.description %>"</center></h2>
<h2><center><%= THIS IS WHERE I WANT TO DISPLAY INFORMATION ON MEALS %></center></h2>
</div>
</div>
If you just want to access the #meals, than you can get it just by for an instance of #chef:
#meals = #chef.meals
given that you have defined the association in the Chef class like following:
class Chef < ActiveRecord::Base
has_many :meals
#rest of the code
end
Have a look at Active Record Associations here.
So, Here I am just giving an example of how to use it in views, you may have to correct it:
in _chef partial
<div class = 'span4'>
<div class = 'chef-box'>
<h2><center><%= link_to chef.name, chef %></center></h2>
<h2><center>"<%= chef.description %>"</center></h2>
<% chef.meals.each do |meal| %>
<h2><center><%= meal.information %></center></h2>
<% end %>
</div>
</div>
You will need to call correct attribute of meal in above sample code.
As previously mentioned – first and foremost make sure the relation is set up in your chef model:
class Chef < ActiveRecord::Base
has_many :meals
end
Then you can call any Chef.meals, whether that's in your controller as:
def index
#chef = Chef.paginate(page: params[:page])
#meals = #chef.meals
end
Or just in your view:
<div class = 'span4'>
<div class = 'chef-box'>
<h2><center><%= link_to chef.name, chef %></center></h2>
<h2><center>"<%= chef.description %>"</center></h2>
<h2>Has <%= pluralize(chef.meals.size, 'meal') %></h2>
<% chef.meals.each do |meal| %>
<% meal.name %>
<% end %>
</div>
</div>
Of note – since Chef is a model name, you should be able to render your _chef.html.erb more cleanly with simply:
<div class = 'chef'>
<div class = 'row'>
<%= render #chef %>
</div>
</div>
<%= will_paginate %>
Note that #chef is singular to match your controller, you could also pass it a collection <%= render #chefs %> if that's what's set up in your controller, and it will do render each chef separately.

Resources