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>
Related
In my application, users submit reviews under brands. Here's the association:
class Brand < ActiveRecord::Base
has_many :reviews
class Review < ActiveRecord::Base
belongs_to :brand
Right now I have a partial defined to show reviews as such:
_showreview.html.erb
<% review.each do |review| %>
<div class="col-sm-4">
<div class="thumbnail">
<%= image_tag review.first_photo %>
<div class="caption">
<h4><%= link_to review.title, review %></h4>
<h6><strong><%= link_to ("WRITTEN BY " + review.user.username.upcase), review.user %></strong></h6>
<%= review.description.truncate_words(60, omission: '...') %>
<br>
<br>
<%= link_to review.brand.label, review.brand, :class => 'btn btn-sm btn-lake' %>
</div>
</div>
</div>
And I render it like this by passing an instance variable in:
<%= render "showreview", review: #top_reviews %>
It works as expected.
Now I wish to reuse the partial for brands/show.html.erb
What I want to do now is retrieve all the reviews that belong to a brand and display it.
show_controller.rb looks like this
def show
#brand = Brand.find(params[:id])
#reviews =Review.find(params[:id])
end
I tried to use this but it doesn't work. What is the correct way to do this?
<%= render "/reviews/showreview", review: '#brand.reviews' %>
<%= render "/reviews/showreview", review: #brand.reviews %>
But please, rename review to reviews. It's more convenient name of this variable.
Your method will be like this
def show
#brand = Brand.find(params[:id])
end
and in your view
<%= render "reviews/showreview", review: #brand.reviews %>
firstly, you should use a plurality for the variable review instead.
reviews.each do |review|
it makes your code readability.
then try placing review: '#branch.review' by reviews: #branch.reviews
and make sure that you did pass the variable #branch from your controller
So in my tutors_controller.rb this is my index action
def index
#tutor = Tutor.all
#tutor = #tutor.fees_search(params[:fees_search]) if params[:fees_search].present?
end
and in my index.html.erb this is the view
<div class='container'>
<%= form_tag(tutors_path, method: :get) do %>
<%= label_tag 'fees_search', 'Max Fees' %>
<%= select_tag 'fees_search', options_for_select((10..50).step(10)) %>
<%= submit_tag 'Filter' %>
<% end %>
<% #tutor.each do |tutor| %>
<% unless tutor.admin? %>
<div class='row' id='tutor-listing'>
<div class='col-xs-4'>
<%= image_tag(tutor.profile.avatar.url, :class => "img-rounded" ) if tutor.profile.avatar? %>
</div>
<div class='col-xs-8'>
<h3><%= link_to tutor.full_name, tutor_path(tutor) %></h3>
<% unless tutor.subjects.nil? %>
<% tutor.subjects.each do |subs| %>
<span class='badge'id='tutor-listing-badge'>
<%= link_to subs.name, subject_path(subs) %>
</span>
<% end %>
<% end %>
<% unless current_tutor %>
<%= button_to "Shortlist Tutor", add_to_cart_path(tutor.id), :method => :post %>
<% end %>
</div>
</div>
<% end %>
<% end %>
</div>
So i understand that when the index view first renders, #tutor would simply be Tutor.all so it renders each individual tutor perfectly.
After trying to filter it though, i start receiving errors. The exact error is NoMethodError in Tutors#indexand the highlighted line is <% unless tutor.admin? %>
profile.rb model
class Profile < ActiveRecord::Base
belongs_to :tutor
scope :fees_to, -> (fees_to) { where("fees_to <= ?", "#{fees_to}") }
end
tutor.rb model
class Tutor < ActiveRecord::Base
has_one :profile, dependent: :destroy
def self.fees_search(n)
#profile = Profile.fees_to(n)
if #profile.empty?
return Tutor.none
else
#profile.each do |y|
y.tutor
end
end
end
end
I get that now my #tutor instance variable has obviously changed. But how do i go about resolving this problem? Should i be rendering a partial instead? Obviously my index action in my controller could be "better" also but i'm quite confused now as to what i should be doing.
Would appreciate any advice! Thank you!
#profile.each do |y|
y.tutor
end
Seems to be a problem. All the other outcomes are a Tutor.something scope, whereas this will return the last tutor only. Change each to map to get an array of Tutors instead.
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;
}
I am trying to build a UI for updating a model ("Profile") that has a many to many relationship with another model ("Category"). The "Category" model has a self referential relationship with itself for "Sub Categories".
In my simple_form I want to display the categories as checkboxes with their sub categories nested below them as check boxes.
In my current code all I have is this for the association field:
= f.association :categories, as: :check_boxes, collection: #categories
I am just retrieving the top level categories into the variable #categories.
I'm not sure where to go from here. What is the best way to do this?
Ancestry
We've done this before using the ancestry gem:
The problem you have is your self-referential association won't give you the scope required to create a "real" nested dropdown; it has to be able to consider all the nested data.
Instead, what we did was to firstly employee the ancestry gem, and then use a partial and helper to get the nested dropdown affect:
#app/models/category.rb
Class Category < ActiveRecord::Base
has_ancestry
end
Display
If you store the dependent data like that, it allows you to create a partial-based nested effect:
#app/views/admin/categories/index.html.erb
<%= render partial: "category", locals: { collection: collection } %>
#app/views/categories/_category.html.erb
<!-- Categories -->
<ol class="categories">
<% collection.arrange.each do |category, sub_item| %>
<li>
<!-- Category -->
<div class="category">
<%= link_to category.title, edit_admin_category_path(category) %>
<%= link_to "+", admin_category_new_path(category), title: "New Categorgy", data: {placement: "bottom"} %>
</div>
<!-- Children -->
<% if category.has_children? %>
<%= render partial: "category", locals: { collection: category.children } %>
<% end %>
</li>
<% end %>
</ol>
Dropdown
#app/helpers/application_helper.rb
Class ApplicationHelper
def nested_dropdown(items)
result = []
items.map do |item, sub_items|
result << [('- ' * item.depth) + item.name, item.id]
result += nested_dropdown(sub_items) unless sub_items.blank?
end
result
end
end
This will allow you to call:
= f.input :categories, as: :select, collection: nested_dropdown(#categories)
How do i get checkbox values in the form from the database? I want the form to bring the existing sub category name,and when i check the checkbox to select that particular category name and not create a new one.I have tried ryan bate's railscast but was no help to me. The realationship here is Category has_many SubCategories and SubCategory belongs_to Category.Thank you.
<%= form_for #category ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :category_name %>
<%= f.fields_for :sub_categories do |s| %>
<% #category.sub_categories.each do |sub|%>
<%=s.check_box "name",{},sub.id %> <!--need help here-->
<%end%>
<%end%>
<%=f.submit "submit"%>
<%end%>
Based on the exchange in the comments, it appears that you want to use the checkboxes to assign SubCategory objects to a Category object. If that's the case, you're association should be that a Category has_and_belongs_to_many :sub_categories. Then your form would look something like:
<%= form_for #category ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :category_name %>
<% SubCategories.each do |sc| %>
<div>
<%= check_box_tag :sub_category_ids, sub_category_id, #category.sub_categories.include?(sc), :name => 'category[sub_category_ids][]' -%>
<%= label_tag :sub_category_ids, sc.name -%>
</div>
<% end -%>
<% end %>
Which will show a category form and then list all of the sub_categories that can be assigned or unassigned by checking the checkboxes.
You will also need a join table "categories_sub_categories" for this new association and logic (likely in your controller) to handle the actual assignment.
example for your category_controller.rb
def create
#category = Category.find(params[:id])
#use the checked sub_category_ids from the form to find and assign the sub_categories.
assigned_sub_categories = SubCategory.find(params[:category][:sub_category_ids]) rescue []
#category.sub_categories = assigned_sub_categories
if #category.save
…
else
…
end
end