Rails 4 - Displaying associated attribute (without all attributes in associated table) - ruby-on-rails

I'm trying to make an app in Rails 4.
I have a profile model.
Im trying to display a user's roles in that profile show page.
I have three models:
User
rolify (which has a user_role join table)
Role
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
Profile
belongs_to :user
In my profile show page, I have:
<%= #profile.user.roles.each do |role| %>
<%= role.name.titlecase %> <span style= "margin-right: 30px"></span>
<% end %>
In the show view, I get:
Manager [#<Role id: 9, name: "faculty_manager", resource_id: nil, resource_type: nil, created_at: "2016-01-16 08:06:55", updated_at: "2016-01-16 08:06:55">]
The 'Manager' part is the only correct part. How do I get the show page not to set out all the other attributes in the role table?

You have <%= #profile instead of just <% #profile which puts result of enumerator in the view
<% #profile.user.roles.each do |role| %>
<%= role.name.titlecase %> <span style= "margin-right: 30px"></span>
<% end %>
If you want to fetch name only for each role then do this
<% #profile.user.roles.pluck(:name).each do |role_name| %>

To set your show page in a nice table view format do something like the following in you show page code:
The error was using <%= #profile.user.roles.each do |role| %>
Note the = you used
<table class="table ld-margin-top-20">
<thead>
<tr>
<th>Manager ID</th>
<th>Manger Name</th>
<th>Manger Resource ID</th>
<th>Manger Resource Type</th>
</tr>
</thead>
<tbody>
<% #profile.user.roles.each do |role| %>
<tr>
<td> <%= role.id %></td>
<td> <%= role.name.titlecase %></td>
<td><%= role.resource_id %></td>
<td><%= role.resource_type %></td>
</tr>
<% end %>
</tbody>
</table>

Related

How can I display values from relationship on column array?

I have 2 tables (users and meetings).
I'm trying to displaying the name of the user on table index view
users
|id| |name|
1 DEMO 1
2 DEMO 2
3 DEMO 3
meetings
|id| |user_id|
1 ["1", "2"]
2 ["2"]
3 ["2", "3"]
The Controller /app/controllers/meetings_controller.erb
def index
#meetings = Meeting.all
end
Models
#meeting.rb
class Meeting < ApplicationRecord
belongs_to :users
end
#user.rb
class User < ApplicationRecord
has_many :meetings
end
The View /app/views/meetings/index.html.erb
<table>
<thead>
<tr>
<td>id</td>
<td>User Names</td>
</tr>
</thead>
<tbody>
<% #meetings.each do |meeting| %>
<tr>
<td><%= meeting.id %></td>
<td><%= meeting.user_id %></td>
</tr>
<% end %>
</tbody>
</table>
I'm trying to display the user_id on array relationship and i tried this code:
I got the following error using the following code
undefined method `each' for "[\"1\", \"2\"]":String
<% meeting.user_id do |array|%>
<%= array.user.name %>
<% end %>
I got the following error using the following code
undefined method `each' for "[\"1\", \"2\"]":String
<% meeting.user_id do |array|%>
<%= array %>
<% end %>
I cannot display the value relationship because of column array.
Can you please help me with this issue?
Thanks in advance.
While there is nothing wrong with your approach, one comes to understand that the path of least resistance (= least pain) is to follow "The Rails Way".
So instead of answering your question, let me suggest that the relationship between your models should be:
# user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :meetings
end
# meeting.rb
class Meeting < ActiveRecord::Base
has_and_belongs_to_many :users
end
# you will also need to create a join table with a migration:
def change
create_join_table :meetings, :users
end
Then the view will include:
<% #meetings.each do |meeting| %>
<tr>
<td><%= meeting.id %></td>
<td><%= meeting.users.map(&:name).join(', ') %></td>
</tr>
<% end %>
I assume that you have a has_many relation between Meeting and User. That means that meeting.users will return the list of the users for the current meeting.
The following will return a comma-separated string with the names.
<table>
<thead>
<tr>
<td>id</td>
<td>User Names</td>
</tr>
</thead>
<tbody>
<% #meetings.each do |meeting| %>
<tr>
<td><%= meeting.id %></td>
<td><%= meeting.users.map(&:name).join(', ') %></td>
</tr>
<% end %>
</tbody>
</table>

How do I use lookup_context to make this view as DRY as possible?

For starters, this is the view I am trying to replicate:
This is the HTML from that layout (from the SAT portion anyway, you can extrapolate the rest):
<table class="table table-hover table-bordered">
<thead>
<td colspan="2" class="text-center">
<strong>SAT</strong>
</td>
<tr>
<th>Subject</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<tr>
<td>Reading</td>
<td>900</td>
</tr>
<tr>
<td>Math</td>
<td>700</td>
</tr>
<tr>
<td>Writing</td>
<td>800</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td><strong>2,400</strong></td>
</tr>
</tbody>
This is what my Grade.rb model looks like:
# == Schema Information
#
# Table name: grades
#
# id :integer not null, primary key
# subject :string
# result :string
# grade_type :integer
# profile_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Grade < ActiveRecord::Base
belongs_to :profile
enum grade_type: { csec: 0, cape: 1, sat: 2, g7: 3, g8: 4, g9: 5, g10: 6, g11: 7, g12: 8, g13: 9 }
end
This is what that table looks like currently, i.e. before using the lookup_context method in Rails:
<table class="table table-hover table-bordered">
<thead>
<td colspan="2" class="text-center">
<strong>SAT</strong>
</td>
<tr>
<th>Subject</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<% #sat_grades.each do |grade| %>
<tr>
<% if grade.subject.eql? "Total" %>
<td><strong><%= grade.subject %></strong></td>
<td><strong><%= grade.result %></strong></td>
<% else %>
<td><%= grade.subject %></td>
<td><%= grade.result %></td>
<% end %>
</tr>
<% end %>
</tbody>
Where #sat_grades is this: #sat_grades = #profile.grades.where(grade_type: :sat).
I want to use this lookup_context method, I was thinking like this:
<% #grades.each do |grade| %>
<% if lookup_context.template_exists?(grade.grade_type, "grades/grade_types", true) %>
<%= render partial: "grade/grade_types/#{grade.grade_type}", locals: {event: event, index: index} %>
<% end %>
<% end %>
The issue I am running into is that each grade_type has a different table. So grade_type: :sat belongs in the "SAT" table, the same for "CSEC", "g11", etc.
I can't think of a way to have each of those grade_types rendered specifically within their HTML table, without having lots of lookup_context.template_exists? calls within that view.
It almost defeats the purpose of doing it like that, if I have to have a lookup_context call for each grade_type.
What's the best way to approach this so I just have 1 lookup_context call (if possible), but it correctly renders and handles all the different grades correctly.
With the given fragment I would try the following:
# Render each grade
<%= render(partial: "grade/grade", collection: #grades, locals: {event: event, index: index}) || "There's grade to be displayed" %>
# Render Concated content
<%= content_for :all_grades %>
Within grade/_grade.html.erb:
# If a special grade template exists prepare the content to be shown
# but don't display it right now
<% if lookup_context.template_exists?(grade.grade_type, "grades/grade_types", true) %>
<%= render partial: "grade/grade_types/#{grade.grade_type}", locals: {event: event, index: index} %>
<% end %>
# Render the common stuff
...
# Display the special stuff stored for the grade
<%= content_for :grade_table %>
# Repeat previous steps
...
Within the grade template (for instance grade/grade_types/_g7.html.erb):
# remove content from previous grades
<% content_for :grade_table, flush: true do %>
...
<% end %>
<% content_for :xxx_xxx, flush: true do %>
...
<% end %>
...
# Concat content for all grades together (flush: false)
<% content_for :all_grades do %>
...
<% end %>
Another approach can be a presenter or maybe even Single Table Inheritance.

Rails Way of Grouping By an Association

I know I am making this more difficult than it needs to be. There has to be a rails way of accomplishing this task. To demonstrate: here are two models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :blogs
def to_s
name
end
end
#app/models/blog.rb
class Blog < ActiveRecord::Base
belongs_to :user
delegate :name, to: :user, prefix: true, allow_nil: true
def to_s
title
end
end
So what I want to do is group all of the blogs by the associated user. Then I want to list those blogs per each user.
Key Detail: not all blogs have an associated user. Some have user_id = nil. Here is a listing of the blogs to demonstrate (last two blogs have user_id = nil):
So I got what I wanted to work. But the solution is not easy to read, and I know there must be some way to accomplish this using Rails' query interface. I couldn't figure it out though, so I hacked together my own solution below:
#app/controllers/admin_controller.rb
class AdminController < ApplicationController
def index
#group_blogs_by_user = {}
User.all.pluck(:name).each{|user| #group_blogs_by_user[user] = []}
#group_blogs_by_user[nil] = [] #provide nil category when no user_id was specified for a blog
Blog.all.each {|blog| #group_blogs_by_user[blog.user_name].push(blog)}
#group_blogs_by_user.reject!{ |_ , v|v.empty?} #do not show users that have no blogs
end
end
And here is the view to display it:
#app/views/admin/index.html.erb
<h1>Showing Count of Blogs per User</h1>
<table>
<thead>
<th>User</th>
<th>Blogs Count</th>
</thead>
<tbody>
<% #group_blogs_by_user.each do |user, blogs_of_this_user| %>
<tr>
<td><%= user || "No User Specified"%></td>
<td><%= blogs_of_this_user.size %></td>
</tr>
<% end %>
</tbody>
</table>
<hr>
<h1>Showing Breakdown of Blogs per User</h1>
<% #group_blogs_by_user.each do |user, blogs_of_this_user| %>
<h3><%= (user || "No User Specified") + " (#{blogs_of_this_user.size} blogs)" %></h3>
<table class="table">
<thead>
<th>Blog ID</th>
<th>Created At</th>
</thead>
<tbody>
<% blogs_of_this_user.each do |blog| %>
<tr>
<td> <%= link_to(blog.id, blog)%></td>
<td> <%= blog.created_at.strftime("%d-%m-%Y")%></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
And here is what it renders, which is what I want:
I run into this situation all the time where I want to group a table by some association, and I find myself continually hacking together a solution. How can I do this the rails way with Rails' Query Interface?
To get all the blogs from a user and print the username, blog_id and blog count
<% #users.each do |user| %>
<%= user.name %>
<%= user.blogs.count %>
<% user.blogs.each do |blog|%>
<%= blog.id %>
<% end %>
<% end %>
To get the amount of blogs with no user
<%= Blog.where(user: nil).count %>
I hope I got your question right and this helps!

Ruby on Rails Render Partial

I have a model called Listing that I use to represent a listing for a sublet. I created a model called Filter that I use to filter the sublets based on a form that the user fills out. Upon filling out the form, I want the user to be redirected to a template that has all of the listings that were returned from the filter.
Here is my Filter model.
class Filter < ActiveRecord::Base
attr_accessible :air_conditioning, :available_rooms, :bathrooms, :furnished, :negotiable, :new, :parking, :maximum_price, :private_bathroom, :show, :term, :total_rooms, :utilities, :washer_dryer
serialize :term
def listings
#listings ||=find_listings
end
private
def find_listings
listings=Listing.order(:price)
listings=Listing.where("listings.price <= ?", maximum_price) if maximum_price.present?
listings=Listing.where(total_rooms: total_rooms) if total_rooms.present?
listings=Listing.where(available_rooms: available_rooms) if available_rooms.present?
listings=Listing.where(bathrooms: bathrooms) if bathrooms.present?
listings=Listing.where(term: term)
listings=Listing.where(furnished: furnished)
listings=Listing.where(negotiable: negotiable)
listings=Listing.where(utilities: utilities)
listings=Listing.where(air_conditioning: air_conditioning)
listings=Listing.where(parking: parking)
listings=Listing.where(washer_dryer: washer_dryer)
listings=Listing.where(private_bathroom: private_bathroom)
listings
end
end
Here is the show method for filter.
<p id="notice"><%= notice %></p>
<%= render (#filter.listings) %>
Pretty simple.
And here is the template called _listing.html.erb
<div style="padding:5px">
<%= link_to 'New Listing', new_listing_path,{:style=>'', :class => "btn"} %>
<h1>Available Sublets</h1>
<table id="listingTable" class="table table-bordered table-hover">
<tr>
<th><%= link_to 'Filter', new_filter_path,{:style=>'', :class => "btn"} %><%= link_to 'Clear Filter', listings_path, {:style=>'', :class => "btn"} %></th>
<th>Address</th>
<th><u><%= "Price Per Month" %></u></th>
<th>Description</th>
</tr>
<% if #listings !=nil %>
<% #listings.each do |listing| %>
<tr onmouseover="this.style.cursor='pointer';"
onclick="window.location.href = '<%= url_for(:controller => 'listings', :action => 'show', :id=>listing.id) %>' " >
<td><%= image_tag listing.photo.url(:small) %></td>
<td><%= listing.address %></td>
<td>$<%= listing.price %></td>
<td width="40%"><%= listing.description %></td>
</tr>
<% end %>
<% end %>
<% else if #listings==nil %>
<p> Sorry, No Sublets Fit Your Criteria! </p>
<% end %>
</table>
However, the filter never returns any results... I have tested atleast 20 times with queries that should definitely return atleast 1 listing. I feel like I have a naming convention problem but I have never used partials before. any help would be great.
This code:
listings=Listing.where(term: term)
listings=Listing.where(furnished: furnished)
listings=Listing.where(negotiable: negotiable)
listings=Listing.where(utilities: utilities)
listings=Listing.where(air_conditioning: air_conditioning)
listings=Listing.where(parking: parking)
listings=Listing.where(washer_dryer: washer_dryer)
listings=Listing.where(private_bathroom: private_bathroom)
Is not actually filtering listings down further. Basically, it's reassigning listings again and again and again.
If you want to apply successive filters to listings, do this:
listings = Listing.where(term: term)
listings = listings.where(furnished: furnished)
listings = listings.where(negotiable: negotiable)
...

Grouping by attributes within a form_for

I am working on a Rails project that requires preferences for diferent user types depending on which shool. Thus i have these models:
class Preference < ActiveRecord::Base
belongs_to :school
belongs_to :privilege
belongs_to :user_type
end
class Privilege < ActiveRecord::Base
has_many :preferences
end
So in my view, i wish to edit the preferences for a given school and i wish to separate and order by user type. So for example my finished view would look like this:
<form accept-charset="UTF-8" action="/preferences/edit" method="post">
<table>
<thead>
<td>Pivilege</td>
<td>Allowed</td>
</thead>
<tbody>
<h2>Student User type</h2>
<tr>
<td>Privilege 1<td>
<td>checkbox for privilege 1<td>
</tr>
<tr>
<td>Privilege 2<td>
<td>checkbox for privilege 2<td>
</tr>
<h2>Employee User type</h2>
<tr>
<td>Privilege 1<td>
<td>checkbox for privilege 1<td>
</tr>
<tr>
<td>Privilege 2<td>
<td>checkbox for privilege 2<td>
</tr>
</tbody>
</table>
</form>
The problem is i do not know how to itarate within a (form_for #preferences do |f|) block and group this array (#preferences) by user_types.
Can anybody help me? Thanxs in advance
I ended up using nested attributes and verifying if the preference belongs to that user type (although I insist that there should be a more "Rails way" of doing it. Hopes this helps somebody:
<%= form_for #school, :url => {:controller => :preferences, :action => :update, :id => #school.id} do |f| %>
<h2>Change Preferences</h2>
<% UserType.all.each do |ut|%>
<h3><%= ut.name%></h3>
<table>
<thead>
<td>Privilege</td>
<td>Allowed</td>
</thead>
<tbody>
<%= f.fields_for :preferences do |pref| %>
<% if pref.object.user_type == ut%>
<tr>
<td><%= pref.object.privilege.name%></td>
<td><%= pref.check_box :allowed, {:allowed => pref.object.allowed} %></td>
</tr>
<% end %>
<% end%>
</tbody>
</table>
<% end %>

Resources