I'm new to Ruby on Rails, and am working on a finance app to aggregate all of my spending. I am collecting all of my data through a form, then showing it all in a different file called show.html.erb. I want to add up all of my spending in show.html.erb, and have so far been able to do it like so:
<strong>Total:</strong>
<td><%= #article.total = (#article.checking_accounts + #article.savings_accounts - #article.debt) %></td>
<td><%= #article.save %></td>
However, because the .save command returns a boolean, I am getting my result on my webpage followed by "true" i.e. "544 true" rather than just 544. How do I save to the database without printing to my webpage?
As already said, you should try to have the least amount of logic in your views.
Normally saving data is done by the Create action in a Controller. So, you should have something like this in your controller:
# articles_controller.rb
...
def create
#article = Article.find(params[:id])
#article.total = #article.checking_accounts + #article.savings_accounts - #article.debt
#article.save
end
def show
#article = Article.find(params[:id])
end
...
And this in your view:
# show.html.erb
...
<strong>Total:</strong>
<td><%= #article.total %></td>
...
You should not put #article.save inside your view, it should be in your controller, or a callback in your model, but since you just starting, I think, for a quick temporary solution, you can do this:
<% #article.total = (#article.checking_accounts + #article.savings_accounts - #article.debt) %>
<% #article.save %>
<strong>Total:</strong>
<td><%= #article.total %></td>
You can use <% ...%> if you want the process to run but do not want it to print. You can use <%= ... %> if you want to print the value.
Related
Inside the console I can access a related table by doing something like this.
#eec = ExpenseExpenseCategory.last
puts #eec.expense.payee.first_name
-> Charles
but inside a template if i have something to the extent of
<% #expense_expense_categories.each do |eec| %>
<tr>
<td><%= eec.amount %></td>
<td><%= eec.expense.payee.first_name %></td>
<\tr>
<% end %>
which is set in my reports controller
def expense_expense_category_report
#expense_expense_categories = ExpenseExpenseCategory.all
respond_to do |format|
format.html {}
format.js {}
end
end
I get this error: ActionView::Template::Error (undefined method `payee' for nil:NilClass):
but, If I call expense such as
<td><%= eec.expense %></td>
I get a relation Expense:0x007f9c8ad91b28> but I get the same error when trying to access it's attributes
<td><%= eec.expense.date %></td>
I get the error ActionView::Template::Error (undefined method `date' for nil:NilClass):
How can I make certain I can access the methods like I do in the console?
It is likely that one or more of your categories does not have an expense associated with it. This sometimes happens to me if I have entered data and then added an association to a model.
This means that it is nil,and you are calling the date on a nil object, which causes your error.
You could check this in the console by running some test code like below
ExpenseExpenseCategory.all.each do |eec|
if eec.expense.nil?
puts "Expense category #{eec.id} has no expense"
end
end
I'm trying to do something very simple with Decorators. I've never personally setup a decorator and I'm trying to spend a bit of time learning about it. Basically I'm trying to take an attribute of a table and build some view logic around it. Here is my code:
Pages Controller:
def dashboard
#assignments = current_account.assignments.all.decorate
#invitation = Invitation.new
end
dashboard decorator:
class AssignmentDecorator < Draper::Decorator
def status
if finished
"Finished"
else
"Waiting"
end
end
end
View table:
<tr class="assignment-rows">
<td><%= link_to assignment.name, account_assignment_path(assignment) %></td>
<td><%= assignment.assigned_workers %></td>
<td><%= assignment.status %></td>
</tr>
As you can see I'm trying to call my assignment method in the td there. but I'm getting this error when I try to render the dashboard:
Use:
#dashboard = Dashboard.find(dasboard_id).decorate
EDIT:
It looks like you want an assignment decorator instead of a dashboard decorator.
Generate a new one with Draper, and then:
#assignments = current_account.assignments.all.decorate
I have a show page where I need to both show the student's units and create a unit for them. However an error is being incurred when trying to do both.
In my controller
def show
#student = Student.find(params[:id])
#unit = #student.units.build
#units = #student.units
end
In my view
<%= simple_form_for #unit, url: student_units_path(#student) %>
# form...
<% end %>
<% #units.each do |unit| %>
<tr>
<td><%= unit.course %></td>
<td><%= unit.mailing_date.strftime('%m/%d/%y') %></td>
</tr>
<% end %>
The unit.course call works and any call that is only the first child of unit, however when I call a second method on unit I get this error:
undefined method `strftime' for nil:NilClass
despite knowing that the unit exists, hence the first call working
It seems your issue is that unit.mailing_date is nil, for newly-built records.
One solution would be to define a default value for mailing_date, either at the database level or in your application. For example, you could do something like:
class Unit < ActiveRecord::Base
# ....
after_initialize :set_default_mailing_date
private
def set_default_mailing_date
self.mailing_date ||= Date.today
end
end
Or alternatively, you could leave the mailing_date as nil and handle this gracefully in the view:
<td><%= unit.mailing_date.try!(:strftime, '%m/%d/%y') %></td>
If you are using ruby version 2.3+, then I would advise using the built-in safe navigation operator, rather than ActiveSupport's try! method:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') %></td>
Finally, if you went with the above choice to leave the mailing_date as nil, then perhaps you'd like to display some default value in its place - for example:
<td><%= unit.mailing_date&.strftime('%m/%d/%y') || 'Not set' %></td>
As an alternative, I assume you don't want the new unit bound to the form being rendered which is what is causing the error.
You could do
#units = #student.units.reject(&:new_record?)
To remove the newly built unit from the collection
Rails 4.x/ ruby 2.x
I am using a checkbox to select records for additional processing. I want to make the checkboxes sticky when using a sort or paginate.
<% #documents.each do |document| %>
<tr>
<td><%= check_box_tag "document_ids[]", document.id %></td>
<td><%= document.id %></td>
<td><%= link_to document.document_title, document %></td>
<removed irrelevent code>
<% end %>
<%= paginate #documents %>
Send Checked Documents as an attachment : <%= submit_tag "Next" %>
The following are the two defs from my controller. If the user simply checked boxes, did not sort or paginate(kaminari), and clicked the next button, the index.multiple def/view would show the documents that were checked.
However, if I check a box and then try to sort or go to the next page, I lose the boxes that were checked, they become unchecked.
def index
#----------------------------------------------------------------
# index is the method for the main documents listing. We need to pass parameters for sorting (sortable in application_helper) and
# kaminari's paginate
#-----------------------------------------------------------------
#documents = Document.all
if params[:direction] && params[:sort] then # missing sort and direction params cause error. This filters for missing and provide a default view
#documents = Document.order(params[:sort] + ' ' + params[:direction]).page params[:page]
else
#documents = Document.order(:id).page params[:page]
end
end
# ------------------------------------------------- index multiple ------------------------------------
def index_multiple
#-------------------------------------------------------------------------
# index multiple is for the page after the index. The user has checked checkboxes and those
# items will be displayed.
# ---------------------------------------------------------------------------------
$doc_ids = params[:document_ids] # get the parameters from the checkboxes. send_message converted the params to integers
if params[:document_ids] then
#documents = Document.find(params[:document_ids])
else
redirect_to documents_path, :notice => "**************** You must select at least one item **************"
end
end
What is the best way to make the checkboxes sticky?
According to rails docs, you can set the checkbox as checked/unchecked using the third parameter: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-check_box_tag
Modify your code to the following and see if it works:
<%= check_box_tag "document_ids[]", document.id, params[:document_ids].include?(document.id) %>
Fresh learning rails, be gentle. No programming experience, but learning.
Building simple app: An app that asks "what's the most important thing you can do right now," gives you an answer field, submits it, and then displays the stored important things.
Ideally, they won't be stored on the index page, but for learning purposes, I'm trying to get them to do this.
Controller code:
class FacilitatesController < ApplicationController
def index
#facilitate = Facilitate.all
end
def new
#facilitate = Facilitate.new
end
def create
#facilitate = Facilitate.new(params[:facilitates])
#facilitate.save
redirect_to #facilitate
end
private
def facilitate_params
params.require(:facilitate).permit(:answer)
end
def show
#facilitate = Facilitate.find(params[:id])
end
end
Index View code:
<h1>Impactful Task Elicitation</h1>
<h1>Listing Stored To dos</h1>
<table>
</table>
<%= link_to 'Store impactful tasks', new_facilitate_path %>
NEW view code:
<h1>What is the most impactful task?</h1>
<p>Store below, motherbiatch</p>
<%= form_for :facilitate, url: facilitates_path do |f| %>
<p>
<%= f.label :answer %><br>
<%= f.text_area :answer %>
</p>
<p>
<%=f.submit 'Save Task' %>
</p>
<% end %>
So far, I can navigate from index, to facilitates/new, and answer the question, to store my important to do. It then takes me to facilitates/33 (ID I'm assuming, or the number that I'm on, task wise)
I'd like to display these tasks both on the facilitates/33 (or whatever number it ends up being) page, as well as the index page.
I've followed directions on a similar type of form here: http://guides.rubyonrails.org/getting_started.html but, I still can't get my stored To do's to display anywhere.
Any help would be awesome.
In your controller, you have the show method below the private line. That means that it can only be called from inside the controller, so you are being sent to the show template without that method ever being called (#facilitate will be nil).
Move the def show method up above the private line.
It then takes me to facilitates/33 (ID I'm assuming, or the number that I'm on, task wise)
The line redirect_to #facilitate, means that after the facilitate is created, go to it's show method and page. The 33 is just a database reference for that particular facilitate, that it can be looked up again with Facilitate.find(params[:id]).
You didn't post what app/views/facilitates/show.html.erb looks like, but if you want to display the newly created facilitate, then it should have a line like this:
<%= #facilitate.answer %>
I'd like to display these tasks both on the facilitates/33 (or whatever number it ends up being) page, as well as the index page.
If you only care about the listing, and not individual facilitates pages, then after creation you can redirect back to the index in the create method by changing redirect_to #facilitate to redirect_to facilitates_path (which translates to '/facilitates').
EDIT:
The <%= #facilitate.answer %> example was meant for the show view, not index.
On index, you'd do something more like this:
<% #facilitate.each do |facilitate| %>
<%= facilitate.answer %><br>
<% end %>
To list them all.