Grouping by attributes within a form_for - ruby-on-rails

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 %>

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>

Trying to display records from chained models on Rails 5.2

Following on from this question
class CoffeeRoast < ApplicationRecord
has_many :coffee_blends
has_many :coffee_beans, through: :coffee_blends
has_one :country, through: :coffee_beans
end
class CoffeeBean < ApplicationRecord
has_many :coffee_blends
has_many :coffee_roasts, through: :coffee_blends
belongs_to :country
end
class Country < ApplicationRecord
has_many :coffee_beans
end
class CoffeeBlend < ApplicationRecord
belongs_to :coffee_bean
belongs_to :coffee_roast
end
I am able to show the related coffee_beans on the coffee_roasts show page, and also the country, however, I can not work out how to display them correctly.
My current code is attempting to show the bean and its related country on the same row on the table, however the top is blank and the two countries are both in the second row.
coffee_roasts/show.html.erb
<h1 class="display-3"><%= #coffee_roast.name %></h1>
<p>
by <h2 class="display-6"><%= #coffee_roast.roaster.roaster_name %></h2>
</p>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Bean</th>
<th>Country</th>
</tr>
</thead>
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<th><%= blend.coffee_bean.name %>
<% end %></th>
<th><%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name }.join(', ') %></th>
</tr>
</tbody>
</table>
Bean | Country
El Martillo |
Finca La Cumbre | El Salvador, Guatemala
El Salvador show be in-line with the El Martillo bean.
My approach feels quite wrong here, but I'm pretty new to working with multiple levels of models so still learning.
How can I get the beans associated country to display alongside the bean?
This was actually a lot simpler than I thought. I've found the below works perfectly. No need to map an array.
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<td><%= blend.coffee_bean.name %></td>
<td><%= blend.coffee_bean.country.country_name %></td> #this bit was the original concern.
<td><%= blend.coffee_bean.variety %></td>
<td><%= blend.coffee_bean.process %></td>
<% end %>
</tr>
</tbody>
<tbody>
<% #coffee_roast.coffee_blends.each do |blend| %>
<tr>
<td><%= blend.coffee_bean.name %></td>
<td><%= #coffee_roast.coffee_beans.map {|cb| cb.country.country_name }.join(', ') %></td>
</tr>
<% end %>
</tbody>
try and see if this works?

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

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>

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!

Rails Has Many Forms

I'm having a bit of trouble getting forms for a has_many association to work for a shopping basket. The view is displaying the basket and has a table row for each item. Each row contains a text field so that the user can set the quantity.
The problem is that only the first item row quantity is being passed through in params, even if the second item's quantity has changed too.
Can anyone help please?
Thanks,
Roger
The output of params in the debugger is below, only one line_item is being passed through.
(rdb:2624) e params
{"commit"=>"Recalculate",
"authenticity_token"=>"7TKnhmbBPFiKLzVqTipzH8PDyCrOnKiFixGQ37XDGNY=",
"_method"=>"put", "utf8"=>"✓", "action"=>"update", "id"=>"4",
"line_item"=>{"quantity"=>"3", "id"=>"6"}, "controller"=>"baskets"}
app/controllers/basket_controller.rb
class BasketsController < ApplicationController
def update
begin
#basket = Basket.find(params[:id])
# Can't do anything here yet since the correct parameters aren't being passed through.
rescue ActiveRecord::RecordNotFound
logger.error "..."
end
redirect_to basket_path
end
end
app/views/baskets/show.html.erb
<%= form_for #basket do |f| %>
<table id="items">
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<% #basket.line_items.each do |item| %>
<%= form_for item do |g| %>
<tr class="<%= cycle('alternate', '') %>">
<td><%= item.product.name %></td>
<td>
<span class="decrement-quantity"><b>-</b></span>
<%= g.text_field :quantity %>
<span class="increment-quantity"><b>+</b></span>
</td>
<td class="price"><%= number_to_currency(item.total_price) %></td>
</tr>
<% end %>
<% end %>
<tr class="totals">
<td>Total</td>
<td><%= #basket.total_quantity %></td>
<td class="price"><%= number_to_currency(#basket.total_price) %></td>
<td></td>
</tr>
</tbody>
</table>
<%= f.submit 'Recalculate' %>
<% end %>
You're just creating a new form within the other form. Rails doesn't do anything magical just because you nest one form within another - which is what's causing the issue you're seeing.
The way to handle this situation is to use the fields_for helper and nested_attributes_for - see NestedAttributes for more information too.
I would checkout Railscasts: Complex Forms Part 1. After you watch that, you may be interested in watching Parts 2 & 3.
Ryan Bates covers using fields_for in an understandable and easy to learn fashion.

Resources