I'm working on a rails app for my expenses.
I have 3 models like : user, spending and currency.
I can create a spending via form, I have a title, description, amount, currency_id, user_id. All the relations are made and working.
I use my show.html.erb from the user controller to display all the expenses from the current_user. That works fine. I then I grouped the expenses together and sort them by date. I did actually 2 groups, the first one which is today and the rest. So on the display it shows me a list of the expenses I created Today (first group) and then a list of month with the expenses from a previous date (second group). For now it shows this :
Today
Expense 1...
Expense 2...
January
...
...
...
December
...
...
etc...
I would like to add the year as well next to the month so that it shows up like this :
Today
...
...
January 2018
...
...
December 2017
...
...
I addition to that I'd like this month and year to be a link so that when you click on it you go to a new page that show all the expenses for this specific month only.
Thats about it. Ah yes, I use will_paginate as well.
Now what I did is this, lets start with my UsersController :
class UsersController < ApplicationController
def show
#user_spendings = #current_user.spendings.all.order('date DESC').paginate(:page => params[:page], :per_page => 10)
#Retrives all messages and divides into two groups todays messages and other messages
#grouped_spendings = #user_spendings.group_by{ |t| t.date.to_date == DateTime.now.to_date }
if #user_spendings.present?
#Create month wise groups of messages
#month_wise_sorted_spendings = #user_spendings.group_by{ |t| t.date.month }
end
end
And my show view is a little bit longer (I didn't paste the will_paginate) :
<% if #grouped_spendings.present? && #grouped_spendings[true].present? %>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<h3>Today</h3>
<tbody>
<% #grouped_spendings[true].each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% if #month_wise_sorted_spendings.present? %>
<% #month_wise_sorted_spendings.each do |hash_elements|%>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<h3><%= Date::MONTHNAMES[hash_elements.first] %></h3>
<tbody>
<% hash_elements.last.each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% end %>
Sorry for that giant code I hope your not blind...
How could I manage to get the month and the year and to make it a link after that. I tried already a few things such as modify this particular line in the show : <%= Date::MONTHNAMES[hash_elements.first] %>. The thing I got is that Date::MONTHNAMES changes the actual month number into the month name and hash_elements.first gives me the actual month number where hash_elements.last gives me all the informations about my expense.
Then I was like, ok, maybe I should go to the controller and add the year over there in this variable #month_wise_sorted_spendings = #user_spendings.group_by{ |t| t.date.month }. This group_by only groups the month for now so I try to add t.date.year, but then in the view I can't use Date::MONTHNAMES. So no success here...
Well I'm a bit lost, any help or hint would be appreciated.
Thanks alot
Ok guys I got everything working !
Maybe some of you want to see how it looks like so there we go
def show
#user_spendings = #current_user.spendings.all.order('date DESC').paginate(:page => params[:page], :per_page => 15)
#Retrives all messages and divides into two groups todays messages and other messages
#grouped_spendings = #user_spendings.group_by{ |t| t.date.to_date == DateTime.now.to_date }
if #user_spendings.present?
#Create month wise groups of messages
#month_wise_sorted_spendings = #user_spendings.group_by{ |t| (Date::MONTHNAMES[t.date.month] + " " + t.date.year.to_s) }
end
end
def detail
if params[:month]
#date = Date.parse("#{params[:month]}") # to get the first day of the month
#user_spendings_month = #current_user.spendings.order('date DESC').paginate(:page => params[:page], :per_page => 30).where(:date => #date..#date.end_of_month) # get posts for the month
#user_amount = Currency.joins(:spendings).
select(:symb, 'SUM(spendings.amount) AS amount').
where(spendings: { id: #user_spendings_month.map(&:id) }).
group(:symb)
else
#user_spendings_month = #current_user.spendings.all.order('date DESC')
end
respond_to do |format|
format.html
format.pdf {
render template: 'views/users/detail', pdf: "eXpenses #{params[:month]}", file: "#{Rails.root}/app/views/users/detail.pdf.erb" }
end
end
I changed the #month_wise_sorted_spendings variable to match my need : the month by name and the year. I also added the def detail as I want to be able to link_to all my months/year to go to a other page and see specific data about this month.
<% if #grouped_spendings.present? && #grouped_spendings[true].present? %>
<table class= "table table-striped table-bordered table-responsive">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<h3 class="btn btn-secondary col-1">Today</h3>
</br></br>
<tbody>
<% #grouped_spendings[true].each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% if #month_wise_sorted_spendings.present? %>
<% #month_wise_sorted_spendings.each do |month,spending|%>
<table class= "table table-striped table-bordered table-responsive">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
</br>
<% date_in_link = " #{month}" %>
<p><%= link_to user_detail_path(#current_user, :month => month), class: "btn btn-secondary col-1" do %>
<i class="fa fa-link"></i>
<%= date_in_link %>
<% end %>
<%= link_to user_detail_path(#current_user, :month => month, format: "pdf"), class: "btn btn-secondary col-1" do %>
<i class="fa fa-file-pdf-o"></i>
PDF
<% end %></p>
</br>
<tbody>
<% spending.each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% end %>
</div>
I use a month param to get the date in the URL and use into the new page via the #user_spendings_month and the #page.
Next to the month/year links I added a link to print a pdf about those infos, I thought it can be handy. I use the same variables I use in the show view in the pdf. Tada ! Just great !
I hope it is clear enough if you don't get something, well just write a comment !
Related
Good afternoon. I am new to ruby and trying to build my first application.
I am using sqlite database and rails 5.0.
I have a model called Person that has the first name, last name and date of birth as attributes.
On the page where I list people I want to add the age of the people and obtain an average of the ages of the people
My controller looks like this:
before_action :set_persona, only: %i[ show edit update destroy ]
# GET /personas or /personas.json
def index
#persona = Persona.order("cast(strftime('%m', fecha_nacimiento) as integer)")
end
And my view like this
<table>
<thead>
<tr>
<th>Nombre</th>
<th>Apellido</th>
<th>Fecha nacimiento</th>
<th>Dni</th>
<th>Edad</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #persona.each do |persona| %>
<tr>
<td><%= persona.nombre %></td>
<td><%= persona.apellido %></td>
<td><%= persona.fecha_nacimiento %></td>
<td><%= persona.dni %></td>
<td><%= Time.now.year - persona.fecha_nacimiento.year %></td>
<td><%= link_to 'Detail', persona %></td>
<td><%= link_to 'Edit', edit_persona_path(persona) %></td>
</tr>
<% end %>
</tbody>
</table>
<p>El promedio de edad de las personas es: </p>
Since I don't have a field in the database called "age" I can't understand how I can achieve the result.
The objective would be to iterate through each of the people and divide it by the length of it, or is there an easier way?
Please excuse my ignorance, thank you very much in advance.
What you want to do is select your calculated column and give it an alias:
def index
#persona = Persona.select(
Persona.arel_table[Arel.star], # personas.*
"cast(strftime('%m', fecha_nacimiento) as integer) as age"
)
.order(age: :desc)
end
Any columns you select will be available in the resulting model instances as attributes:
<table>
<thead>
<tr>
<th>Nombre</th>
<th>Apellido</th>
<th>Fecha nacimiento</th>
<th>Dni</th>
<th>Edad</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #persona.each do |persona| %>
<tr>
<td><%= persona.nombre %></td>
<td><%= persona.apellido %></td>
<td><%= persona.fecha_nacimiento %></td>
<td><%= persona.dni %></td>
<td><%= persona.age %></td>
<td><%= link_to 'Detail', persona %></td>
<td><%= link_to 'Edit', edit_persona_path(persona) %></td>
</tr>
<% end %>
</tbody>
</table>
The easiest way to implement what you're asking is to do the operation within the view. This kind of breaks MVC but it's the fastest.
<% edades = 0 %>
<% #persona.each do |persona| %>
<% edades += Time.now.year - persona.fecha_nacimiento.year %>
<!-- ... the rest of the view code -->
<% end %>
<% average = edades.to_d / #persona.length # need to typecast to decimal so you can have fractionals %>
To do this in an MVC manner, you will have to do the computation in the controller.
def index
#persona = Persona.order("cast(strftime('%m', fecha_nacimiento) as integer)")
#average = #persona.collect { |p| Time.now.year - p.fecha_nacimiento.year }.sum / #persona.length.to_d
end
It would be easier to implement an age method in Person model so you can just call the method instead.
class Person
def edad
Time.now.year - fecha_nacimiento.year
end
end
and lastly, the computation for the age is more complex than just current year less birthday year. We use this function (taken from https://stackoverflow.com/a/2357790/365218) to calculate for the age.
def age(dob)
now = Time.now.utc.to_date
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end
I'm creating a rails app for my expenses. I have several models like user, spending, currency. I put relations between them, everything works. I can add a new expense that is shown on a index (all the expenses from all users) and I decided to loop through the expenses on the user show page, where the current_user see his own expenses.
I also grouped the expenses by date (month and year) and I have a "Today" group, which shows all the expenses entered on the day. It looks like this in the controller :
def show
#user_spendings = #current_user.spendings.all.order('date DESC').paginate(:page => params[:page], :per_page =>
10)
#Retrives all messages and divides into two groups todays messages and other messages
#grouped_spendings = #user_spendings.group_by{ |t| t.date.to_date == DateTime.now.to_date }
if #user_spendings.present?
#Create month wise groups of messages
#month_wise_sorted_spendings = #user_spendings.group_by{ |t| (Date::MONTHNAMES[t.date.month] + " " + t.date.year.to_s) }
end
end
This is my view :
<% if #grouped_spendings.present? && #grouped_spendings[true].present? %>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<h3>Today</h3>
<tbody>
<% #grouped_spendings[true].each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% if #month_wise_sorted_spendings.present? %>
<% #month_wise_sorted_spendings.each do |hash_elements|%>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Amount</th>
<th>Currency</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<% date_in_link = "#{hash_elements.first}" %>
<h3><%= link_to(date_in_link, detail_result_path) %></h3>
<tbody>
<% hash_elements.last.each do |spending| %>
<tr>
<td><%= spending.title %></td>
<td><%= spending.description %></td>
<td><%= '%.02f' % spending.amount %></td>
<td><%= spending.currency.symb %></td>
<td><%= spending.date.strftime('%d %B %Y') %></td>
</tr>
</tbody>
<% end %>
</table>
<% end %>
<% end %>
I would like to create a link on the month and year and open a page where all the informations are looped again but only for this specific month of the year.
I already achieved the linking with this :
<% date_in_link = "#{hash_elements.first}" %>
<h3><%= link_to(date_in_link, detail_result_path) %></h3>
To avoid mixing the controllers etc... I decided to create new controller called detail and a result.html.erb page where I will loop the expenses about the specific month and year.
Which way should I take with this ? Is it a good option to do a new controller ? And how can I get the infos back according to the date on my new page ?
I thought about passing some params via the link_to but I'm not sure it's the best solution. Maybe there is something easier but I don't know or see it.
If anyone can help would be great !
Thanks alot
I found the answer but it's on a other post I did as I had an other problem before this one. So the link is here
Feel free to ask question if any
I am trying to submit a grid form like the below one,
show.html.erb
<%= form_for :datadef, url: update_all_vmodule_path do |fdf|%>
<table id="csvfiles" class="display" width="100%">
<thead>
<tr>
<th width="10%">Column No</th>
<th width="20%">Column name</th>
<th width="20%">Data type</th>
<th width="15%">Column format</th>
<th width="10%">Length</th>
<th width="25%">Comments</th>
</tr>
</thead>
<tbody>
<% #datadefrecords.each do |ddre| %>
<%= fields_for "datadef_records[]", ddre do |dr_fld| %>
<tr>
<td><%= ddre.column_no %></td>
<td><%= ddre.column_name %></td>
<td><%= dr_fld.collection_select :column_datatype, Datadef.select(:column_datatype).uniq, :column_datatype, :column_datatype, {:prompt => true} %> </td>
<td><%= dr_fld.text_field :column_format %></td>
<td><%= dr_fld.text_field :column_length %></td>
<td><%= dr_fld.text_field :comments %></td>
</tr>
<% end %>
<% end %>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td colspan="2"><%= fdf.submit 'Save' %> <%= link_to("<button>Cancel</button>".html_safe, cancelmodal_vmodule_path ) %></td>
</tr>
</tbody>
</table>
<% end %>
<% end %>
This the method i am calling it to submit
def update_all
session[:datadef] = nil
#updatedatadef = Datadef.all.where(:id => params[:datadef_records]).update_all(update_all_params)
redirect_to migproject_path(params[:vmodule][:migproject_id])
end
This is the strong parameters
def update_all_params
params.require(:datadef_records).permit( :column_datatype, :column_format, :column_length, :comments)
end
This is how i get the parameters from form
{"utf8"=>"✓",
"authenticity_token"=>"QrX8JYYYQOlfwKgAABJd0+A7VpugS2Y6n8doDsuKqeM=",
"datadef_records"=>{"12"=>{"column_datatype"=>"varchar",
"column_format"=>"2",
"column_length"=>"2",
"comments"=>"2"},
"13"=>{"column_datatype"=>"varchar",
"column_format"=>"2",
"column_length"=>"2",
"comments"=>"2"}},
"commit"=>"Save",
"id"=>"2"}
But i get this "Empty list of attributes to change" error which is not allowing me to write it in table. And i am not able to identify what could be the error.
Thanks in advance.
I think the problem is to do with your use of update_all, although I'm not 100% sure as to the syntax of the problem.
From what I understand, update_all needs a hash of actual params to populate your data; even then, it will only update what you pass to it (kind of like update_attributes).
Here's a good reference:
data = params[:datadef_records]
#updatedatadef = Datadef.update(data.keys, data.values)
This negates the use of your strong_params, which I'd recommend using. I'd have to spend some time thinking about getting it to work.
Iam having an issue getting data from two different database tables to display properly with in an HTML table. I'm sure I am just overlooking something and this is pretty easy, but for whatever reason I cannot get quantity to display, or the <td class="sub-total"> to display either.
Demands (you can think of these as orders) and items are connected through a table called demand_items. The demand_items table also has the quantity of the item ordered. The page will display but the quantity and the subtotal will not render.
Here is the html:
<h3>Order for <%= #demand.customer.name %></h3>
<h4>Ordered for: <%= #demand.date %></h4>
<h4>Add Items</h4>
<%= render 'demands/item_form' %>
<table class="customer-table">
<tr>
<th>Item</th>
<th>Price</th>
<th>Quantity</th>
<th>Sub Total</th>
</tr>
<% #demand.items.each do |item| %>
<tr>
<td><%= item.name %></td>
<td><%= item.price %></td>
<% #demand.demand_items do |quantity| %>
<td><%= quantity.quantity %></td>
<td class="sub-total"><%= (item.price) * (quantity.quantity) %></td>
<% end %>
<% end %>
</tr>
</table>
#demand.demand_items.each do |quantity|..........instead of #demand.demand_items do |quantity|......
I have a loop in one of my views to display a table like so:
Each category object has 5 attributes called: level_1, level_2, level_3, level_4, level_5.
There will be an array with all the category objects. so there could be any amount of categories and no necessarily 3.
what would the best way to draw this up be? i have something like this at the moment but dont know how to select the relevant category level attribute in the 5.times loop.
<table border="0">
<tr>
<th>Maturity</th>
<% for category in #categories %>
<th><%= category.category_title %></th>
<% end %>
</tr>
<% 5.times do |i|%>
<% level = 5 - i %>
<tr>
<td>Level <%= level %> Maturity</td>
<% for category in #categories %>
<td><%= category.level_ #put in the level value here so it selects the relevant attraibute %></td>
<% end %>
</tr>
<% end %>
</table>
you need to change the rendering of level with this:
<% for category in #categories %>
<td><%= category.send("level_#{level}") %></td>
<% end %>
send is used to call a method on an object so that you can compose your method at runtime.
If you categories as variable no. then you shouldn't make it columns, but rows. And then levels will be you columns e.g.
<table>
<tr>
<th>Level 1</th>
<th>Level 2</th>
<th>Level 3</th>
<th>Level 4</th>
<th>Level 5</th>
<tr>
<% #category.each do |c| %>
<tr>
<td>#category.level_1<td>
<td>#category.level_2<td>
<td>#category.level_3<td>
<td>#category.level_4<td>
<td>#category.level_5<td>
<th>
<% end %>
Now in above code you may replace hard coded level_#{no} with iterations.