Jeremy Bray
Jeremy Bray

Reputation: 444

Calculate Monthly Totals

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

Answers (2)

Anand
Anand

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

barmic
barmic

Reputation: 1097

Modify your model method in this way:

def total_monthly_payment
    n = current_user.credit_cards.sum(&:minimum_payment)
end

Upvotes: 2

Related Questions