Hi in my apps I have a scaffold, were users can select different type of paper and add a paper weight for each type. Then I calculate the running total of paper_weight for each user in the ApplicationController.
I want to be more specific and show the users the average weight of each paper_type they are using. I´m a bit lost since I ´m rather new to rails, can anyone here help me??
thanks in advance
below are my views.
in paper/new.html.erb
<div class="control-group">
<%= f.label :paper_type, class: 'control-label' %><br>
<div class="controls">
<%= f.select(:paper_type, options_for_select([['Skrifstofupappír', 'Skrifstofupappír'], ['Dagblaðapappír', 'Dagblaðapappír'], ['Glans_&_tímaritapappír', 'Glans_&_tímaritapappír'], ['Annað', 'Annað']])) %>
</div>
</div>
<div class="control-group">
<%= f.label :paper_weight, class: 'control-label' %><br>
<div class="controls">
<%= f.number_field :paper_weight %>
</div>
</div>
in ApplicationController.rb
#paper_weight_per_capita = current_user.papers.sum(:paper_weight) / (current_user.profile.staff)
First a tweak.
In your Paper class is where you want to put the array of acceptable values for the paper type. That way you can validate input from perhaps more than just this form in the future. It also allows you to test that code plus putting an array right in the view like that is just not the best practice.
class Paper
PAPER_TYPES = ['Skrifstofupappír', 'Dagblaðapappír', 'Glans_&_tímaritapappír', 'Annað']
...
Then in your view, change to this.
<%= f.select(:paper_type, options_for_select(Paper::PAPER_TYPES)) %>
That doesn't answer your question, just a tweak to make your code cleaner and testable.
Then in your User model
def average_paper_types
self.papers.group(:paper_type).sum(:paper_weight)
end
And in your partial:
<table>
<thead>
<tr>
<% current_user.average_paper_types.each do |pair| %>
<th><%= pair[0] %></th>
<% end %>
</tr>
</thead>
<tbody>
<tr>
<% current_user.average_paper_types.each do |pair| %>
<td><%= pair[1] %></td>
<% end %>
</tr>
</tbody>
</table>
Not positive I understand correctly, but I think what you're trying to do (based on comments) is display the averages of each individual paper type on the index page.
As you're iterating through the different types of paper that belong to the user, you could call a method that performs that calculation. Inside that method you might do something like this:
def paper_weight_by_type(user_id, paper_type)
u = User.find(user_id)
weight_by_type = Paper.where(user_id: user_id, paper_type: paper_type).pluck(:paper_weight)
# then return this
weight_by_type.inject(:+)
end
this is a crude version. This could be an instance method on either user or paper in which case you wouldn't need both arguments. (ie current_user.paper_weight_by_type(paper_type) ...could also make it a class method and just pass both arguments by adding self. in front of def) Also several ways you could probably cut down on the number of queries being run...but this would get the job done. You'd want to call it from the paper loop on the index page however you ended up doing it. I would get it working one way and then improve it from there. Hope this helps.
Related
I want to order the Conversation model, using a custom method.
I found some solution:
How do you order by a custom model method that has no attribute in SQL?
and
http://awaxman11.github.io/blog/2013/10/11/sorting-a-rails-resource-based-on-a-calculated-value/ ,
but Conversation order have priority.
First- answer_percent desc,
second- order to last_answer time
(using custom model method last_answered_to_i ).
last_answered_to_i method source:
def last_answered_to_i
if Conversation.where(company_id: self.id, is_answered: true).present?
last_conversation = Conversation.where(company_id: self.id, is_answered: true).first
if last_conversation.answered_at.blank? || last_conversation.asked_at.blank?
minutes = (Time.now- last_conversation.updated_at)/1.minutes
else
minutes = (last_conversation.answered_at - last_conversation.asked_at)/1.minutes
end
minutes.to_i
else
nil
end
end
after ordering I want add pagination using kaminari gem.
#lists = Company.searchable.order("answer_percent desc").page(params[:page]).per(20)
How do I order by column and custom method and add pagination?
I think the answer depends on what you want to see in the view because some of the problem could actually be solved in how you call #lists there. Also, some of the links you found make sorting by a model method sound more difficult than it is.
In your case, you can sort your conversations by a custom method like so:
Conversation.all.sort_by(&:custom_method)
Or specifically:
Conversation.all.sort_by(&:last_answered_to_i)
Specifically, you cannot use SQL to sort or order by something not in the actual database, so you use the Ruby sort_by method. For more info on the ampersand, see this post.
For your actual view, I'm not sure really how you want to organize it. I recently did something where I needed to group my resource by another resource called "categories", and then sort the original resource by "netvotes" which was a custom model method, then order by name. I did it by:
Ordering by name in the controller: #resources = Resource.order(:name)
Grouping by category in the outer loop of the view: <% #resources.group_by(&:category).each do |category, resources| %>
Then sorting the resources by votes in the partial for resources: <%= render resources.sort_by(&:netvotes).reverse %>
The view is a bit confusing, so here is the full view loop in index.html.erb:
<% #resources.group_by(&:category).each do |category, resources| %>
<div class="well">
<h3 class="brand-text"><%= category.name %></h3>
<%= render resources.sort_by(&:netvotes).reverse %>
</div>
<% end %>
And here is the _resource.html.erb partial:
<div class="row resource">
<div class="col-sm-2 text-center">
<div class="vote-box">
<%= link_to fa_icon('chevron-up lg'), upvote_resource_path(resource), method: :put %><br>
<%= resource.netvotes %><br>
<%= link_to fa_icon('chevron-down lg'), downvote_resource_path(resource), method: :put %>
</div>
</div>
<div class="col-sm-10">
<%= link_to resource.name, resource.link, target: "_blank" %>
<p><%= resource.notes %></p>
</div>
</div>
I hope that helps you think through some more ways to address your problem.
I've ran into a bit of a problem. I watched Railscasts 370 and discovered a cool new gem called ransack
My problem is it's not doing what I want it to do, which is to filter a table based on a search
Here is my controller
def index
#search = Component.ransack(params[:q])
#components = #search.result
end
And my view
<%= search_form_for #search do |f| %>
<%= f.label :name_cont %>
<%= f.search_field :name_cont %>
<%= f.submit "Search" %>
<% end %>
When I typed in "Gigabyte" and clicked search, I saw the following in the URL
http://localhost:3000/components?utf8=%E2%9C%93&q%5Bname_cont%5D=Gigabyte&commit=Search
I know that this is URL syntax for a query. And it refreshes the page as well. Problem is, I see the following three results
Intel Core i5-4460 3.2GHz Quad-Core
Gigabyte GA-Z97X-SLI ATX LGA1150
Team Elite Plus 8GB (2 x 4GB) DDR3-1600 Memory
These were the names of the 3 items in my table. I expected only one result to return from this query.
If it helps, I've added part of my Development Logs
Processing by ComponentsController#index as HTML
Paramaters: {"utf8=>"checkmark", "q" => {"name_cont"=>"Gigabyte"}, "commit"=>"Search"
It shows up in the parameters too, so I'm completely mystified as to why my code's not working. Any help will be greatly appreciated.
EDIT
I think I found the problem but I'm not sure
I have this inside <tbody>
<tbody>
<% Component.all.each do |c| %>
<tr>
<td> <strong><%= c.part %></strong> </td>
<td> <a id="links" href="<%=c.link%>"> <%= c.name %> </a></td>
<td> $<%= c.price %> </td>
</tr>
<% end %>
</tbody>
EDIT
Looks like that was indeed my mistake. Changing Component.all to #components.each fixed it.
Have you tried to change this
#search = Component.ransack(params[:q])
for this?:
#search = Component.search(params[:q])
I've been using the gem recently and probably the gem changed a little with regard the railscast
I have a table in view:
#view
<%= form_tag save_table_path do %>
<table>
<% #channel_name_body.values.max_by(&:size).size.times do |i| %>
<tr class="border">
<% #channel_name_body.values.map { |a| a[i] }.each do |value| %>
<td contenteditable class="border light_green"><%= value %></td>
<% end %>
</tr>
<% end %>
</table>
<%= submit_tag "save",:class => "btn btn-primary offset4" %>
<% end %>
I don't know what to do next to pass value of all cell in table to controller such as:
#controller
def save_table
#table=params[:table] #or #row1=params[:row1]... or #col1=params[:col1]....
end
Edit: I found way to solve this problem, it must use js.
I don't want to use js, what about if I change to <%= text_field_tag :cell, value %> how can I get value of all cell in table ?
I think you're getting confused with how to handle data in Rails (or any backend system)
HTML
HTML is a markup language; which means if you give it certain code, it will put various elements onto the page. The <table> tag is one of those elements, and has no bearing on the controller-side functionality of your app
Controller Params
HTML form params are directly related to the form (nothing else)
In Rails, you get the params hash ordered like this:
params[:form_name][:input_name]
Your Code
From what you've shown, it seems you have several parts missing
Firstly, you need input elements (to populate the params). Currently, you have:
<td contenteditable class="border light_green"><%= value %></td>
This does not create any params, as it's not an input element. It's just a value that's been outputted on the screen. What you'd need is something like:
<td contenteditable class="border light_green"><%= text_field_tag :cell, :value => value %></td>
By adding these inputs, you will give Rails the ability to populate the params hash with their values, which you can then access from your controller like this:
def save
#table = params[:form_name][:cell][0]
end
Hope this helps?
Try this:
<%= text_field_tag "table[cell#{index}]", value %>
On form submit it will give you values like params[:table][:cell1], params[:table][:cell2] and so on...
Hope this helps..
So I'm trying to combine two tables and show the results in order of the start_date.
I've tried a few things but because its technically a nested loop its giving me double results for each item.
The code i currently have is as follows
<% #subcategory = Subcategory.all %>
<% #product = Product.all %>
<% (#product + #subcategory).each do |product, subcategory|%>
<% if product.display_on_home_page and !product.is_highlight_product and !(product == '..') or subcategory.
display_on_home_page and !subcategory.is_highlight_product and !(subcategory == '..')%>
<div class="column_entry">
<%= link_to image_tag(subcategory.image_attachment.url(:normal_page_size)), subcategories_content_url(subcategory.id), :controller=>'subcategories' %>
</div>
<% end %>
<% if product.price_from %>
<div class="column_entry">
<div class="product_special">
<span class="a">From Only</span>
<span class="b"><%= number_to_currency(product.price,:unit=>'€') %></span>
</div>
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id), :controller=>'products' %>
</div>
<% else %>
<div class="column_entry">
<div class="product_special">
<span class="a">Only</span>
<span class="b"><%= number_to_currency(product.price,:unit=>'€') %></span>
</div>
<%= link_to image_tag(product.product_image.url(:normal_page_size)), products_content_url(product.id), :controller=>'products' %>
</div>
<% end %>
<% end %>
I know this is quite a long an complex statement, its supposed to loop through all of the subcategories and all of the products and display the images, there are also two different ways of displaying the price based on a boolean that says whether the price is a specific amount or it starts from a given price.
at the moment its reading through the loop but its giving me the error
undefined method `is_highlight_product' for nil:NilClass
since this is the first column in the table that is referenced and its breaking here I think that there must be some conflict in its ability to see the information stored in the table.
I'm still quite new to ruby on rails so any help or even just a nudge in the right direction would be very much appreciated.
If you would like more information just ask in the comments and I'll put it up as fast as I can.
The problem here is, when you do something like this:
(#product + #subcategory).each do |product, subcategory|
The local variable product will iterate firstly through products, then through subcategories, and the local variable subcategory will always be nil.
What you can do, a dirty way - check
if product.is_a?(Product)
# do your things
elsif product.is_a?(Subcategory)
# do other things
end
I have three models Vote, Option and Number. I set up an index to input voting information such as title and description. How do I store the number of votes (in the Number model) using radio buttons?
My models have the following attributes:
Vote: name, description
Option: vote_id, content
Number: option_id, content (integer)
here is my edit.html
i want to add vote-number function in this html,but i don't know how.so Can You give me some ideas to finish it? ^_^.i'm new in rails ,and thank you very much for helping me !!
<p id="notice"><%= notice %></p>
<p>
<b>Name:</b>
<%= #vote.name %>
</p>
<p>
<b>Description:</b>
<%= #vote.description %>
</p>
<% for option in #vote.options %>
<%=h option.content %><br />
<% end %>
<%= link_to 'Back', votes_path %>
This might point you in the right direction:
http://railscasts.com/episodes/196-nested-model-form-part-1
You'll want to use *fields_for* within your input form, and pass your second model to it.
Rails should take care of the magic in the backend if your model association relationships (belongs_to, has_many etc.) have been set up correctly.