Reputation: 444
Hello I am creating a little app to help me manage my credit cards.
I have a User Model and a Credit Card Model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :credit_cards
end
class CreditCard < ApplicationRecord
belongs_to :user
def credit_available
limit - balance
end
def annual_interest
if self.balance && self.interestRate
self.balance * self.interestRate
else
"0.0".to_d
end
end
def minimum_payment
n = balance / 100
b = n * 1
i = balance * interestRate
c = i / 12
c + b
end
end
As you can see I have calculated a methods including monthly_payment in my credit_cards model
Now I want to total my credit card payments on a monthly basis. so I added another method to my credit cards model called total_monthly_payment which totals the current_users credit_card monthly_payments into a sum.
def total_monthly_payment
n = current_user.credit_cards.sum(minimum_payment)
n
end
the view sits like so
<% if user_signed_in? %>
<h1>Credit Cards</h1>
<% if current_user.credit_cards.any? %>
<table class="mdl-data-table mdl-js-data-table">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric"><%= link_to 'Name', :sort => 'card_NickName' %> </th>
<th class="mdl-data-table__cell--non-numeric"><%= link_to 'Provider', :sort => 'card_provider' %></th>
<th class="mdl-data-table__cell--non-numeric"><%= link_to 'Points', :sort => 'points_provider' %></th>
<th>%</th>
<th>Balance</th>
<th>Limit</th>
<th>Available</th>
<th>Min Payments</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @credit_cards.each do |credit_card| %>
<tr>
<td class="mdl-data-table__cell--non-numeric"><%= link_to credit_card.nickName, credit_card %></td>
<td class="mdl-data-table__cell--non-numeric"><%= credit_card.provider %></td>
<td class="mdl-data-table__cell--non-numeric"><%= credit_card.pointsProvidor %></td>
<td><%= number_to_percentage(credit_card.interestRate * 100, precision: 2) %></td>
<td><%= number_to_currency(credit_card.balance, unit: "$") %></td>
<td><%= number_to_currency(credit_card.limit, unit: "$") %></td>
<td><%= number_to_currency(credit_card.credit_available, unit: "$") %></td>
<td><%= number_to_currency(credit_card.minimum_payment, unit: "$") %></td>
<td></td>
<td></td>
<td></td>
</tr>
<% end %>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td><%= number_to_currency(@credit_card_debt, unit: "$") %></td>
<td><%= number_to_currency(@credit_limit, unit: "$") %></td>
<td><%= number_to_currency(@available_credit, unit: "$") %></td>
<td><%= @total_monthly_payment %></td>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
<br>
<%= link_to new_credit_card_path, class: 'mdl-button mdl-js-button mdl-button--fab mdl-button--colored' do %>
<i class="material-icons">add</i>
<% end %>
<% else %>
You have no Credit Cards, better
<%= link_to new_credit_card_path, class: 'mdl-button mdl-js-button mdl-button--fab mdl-button--colored' do %>
<i class="material-icons">add</i>
<% end %>
one.
<% end %>
<% else %>
<div class="mdl-cell mdl-cell--2-col mdl-cell--2-col-tablet"></div>
<div class="mdl-cell mdl-cell--8-col mdl-cell--8-col-tablet"><h1>Credit Card Smarts at your fingertips</h1></div>
<div class="mdl-cell mdl-cell--2-col mdl-cell--2-col-tablet"></div>
<% end %>
all works well untill i try to calculate the @total_monthly_payment when i get the following error.
NameError in CreditCardsController#index
undefined local variable or method `balance' for #<CreditCardsController:0x00007fc18f7dfa48>
Extracted source (around line #5):
3
4
5
6
7
8
def minimum_payment
n = balance / 100
b = n * 1
i = balance * interestRate
c = i / 12
controller
class CreditCardsController < ApplicationController
before_action :authenticate_user!
before_action :set_credit_card, only: [:show, :edit, :update, :destroy]
# GET /credit_cards
# GET /credit_cards.json
def index
@credit_cards = current_user.credit_cards
@credit_card_debt = current_user.credit_cards.sum(:balance)
@credit_limit = current_user.credit_cards.sum(:limit)
@available_credit = current_user.credit_cards.sum(:limit) - current_user.credit_cards.sum(:balance)
@total_monthly_payment = total_monthly_payment
end
# GET /credit_cards/1
# GET /credit_cards/1.json
def show
end
# GET /credit_cards/new
def new
@credit_card = current_user.credit_cards.build
end
# GET /credit_cards/1/edit
def edit
end
# POST /credit_cards
# POST /credit_cards.json
def create
@credit_card = current_user.credit_cards.new(credit_card_params)
respond_to do |format|
if @credit_card.save
format.html { redirect_to @credit_card, notice: 'Credit card was successfully created.' }
format.json { render :show, status: :created, location: @credit_card }
else
format.html { render :new }
format.json { render json: @credit_card.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /credit_cards/1
# PATCH/PUT /credit_cards/1.json
def update
respond_to do |format|
if @credit_card.update(credit_card_params)
format.html { redirect_to @credit_card, notice: 'Credit card was successfully updated.' }
format.json { render :show, status: :ok, location: @credit_card }
else
format.html { render :edit }
format.json { render json: @credit_card.errors, status: :unprocessable_entity }
end
end
end
# DELETE /credit_cards/1
# DELETE /credit_cards/1.json
def destroy
@credit_card.destroy
respond_to do |format|
format.html { redirect_to credit_cards_url, notice: 'Credit card was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_credit_card
@credit_card = CreditCard.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def credit_card_params
params.require(:credit_card).permit(:nickName, :provider, :pointsProvidor, :interestRate, :balance, :limit, :user_id )
end
end
Please help!
Upvotes: 1
Views: 79
Reputation: 6531
Just a side note: -
n = current_user.credit_cards.sum(&:minimum_payment)
first it will get an array of all credit_card's minimum_payment and then this will iterate over this array one by one and loop through it. so for 100 or 1000 records its not efficient way.
For this you should use sql query: -
n = current_user.credit_cards.sum(:minimum_payment)
which will fire sql query only, some how like this : -
SELECT SUM(credit_cards
.minimum_payment
) FROM credit_cards
Upvotes: 1
Reputation: 1097
Modify your model method in this way:
def total_monthly_payment
n = current_user.credit_cards.sum(&:minimum_payment)
end
Upvotes: 2