Promise Preston
Promise Preston

Reputation: 29088

Rails: Calling methods in a model in a different controller

Please, I really don't know how best to achieve refactoring this code following the best rails practices. I am trying to call some methods that are defined in a model in my rails application in a different controller.

I have a Donations model and a Dashboard Controller and I would like to display some data about donations on the dashboard. I want to achieve this by defining the data that I want in some methods and scopes in the Donations model and then call them in the Dashboard controller and then make them available in the *Dashboard views**.

But I realized that no data about donation gets displayed on the dashboard, which may be as a result of the fact that the methods in the Donations model doesn't get exposed or are not available to the Dashboard controller when they are called, since they are a different model and different controller.

Here is my code

Donations Model

class Donation < ApplicationRecord
  belongs_to :program
  scope :paid_count, -> { where(payment: true).count }
  scope :unpaid_count, -> { where(payment: false).count }
  scope :paid_sum, -> { where(payment: true).sum(:amount) }
  scope :deployed_sum, -> { where(deployment: true).sum(:amount) }
  scope :not_deployed_sum, -> { where(deployment: false, payment: true).sum(:amount) }

  def self.deployed_donations_percent
    (deployed_sum.to_f / paid_sum.to_f) * 100
  end

  def self.not_deployed_donations_percent
    (not_deployed_sum.to_f / paid_sum.to_f) * 100
  end
end

Dashboard Controller

class DashboardController < ApplicationController
  def index
    # Paid Donations in Chart
    @paid_donations = Donation.paid_count
    # Unpaid Donations in Chart
    @unpaid_donations = Donation.unpaid_count
    # Total Donations Sum
    @total_donations_sum = Donation.paid_sum
    # Deployed Donations
    @deployed_donations = Donation.deployed_sum
    # Not Deployed Donations
    @not_deployed_donations = Donation.not_deployed_sum
    # Deployed Donations Percentage
    @deployed_donations_percent = Donation.deployed_donations_percent
    # Not Deployed Donations Percentage
    @not_deployed_donations_percent = Donation.not_deployed_donations_percent
    @total_donations = Donation.count
    # Paid Donations
    @paid_donations = Donation.paid_count
    # Unpaid Donations
    @unpaid_donations = Donation.unpaid_count

    # All Programs
    @programs = Program.all
  end
end

Dashboard Index

<h2>
    DASHBOARD
</h2>

  <h4>Overall Donations</h4>
  <%#= area_chart @donations.map { |pay|{name: pay.payment, data: @donations.where(payment: pay).group_by_day(:created_at).count}}, discrete: true %>
  <%= line_chart Donation.group(:payment).group_by_day(:created_at).count

   <h4>Total Donations</h4>
    <%= number_with_delimiter(@total_donations_sum, :delimiter => ',') %>

    <h4>Deployed</h4>
     <%= number_with_delimiter(@deployed_donations, :delimiter => ',') %>

    <div>
      <%= @deployed_donations_percent.round %>>
    </div>

    <h4>Undeployed</h4>
    <%= number_with_delimiter(@not_deployed_donations, :delimiter => ',') %>

    <div>
      <%= @not_deployed_donations_percent.round %>
    </div>

<h4>Total Donations</h4>
<header>
  <%= @total_donations %>
</header>

<h4>Paid Donations</h4>
<header>
  <%= @paid_donations %>
</header>

<h4>Unpaid Donations</h4>
<header>
  <%= @unpaid_donations %>
</header>

PROGRAMS
<td>Program Name</td>
<td>Sponsored</td>

</tr>
  <% @programs.each do |program| %>
<tr>
    <td><%= program.name %></td>
<td><%= program.donations.count %></td>

Please, I would greatly appreciate some help on how to refactor this code and get the Donations model methods exposed to the Dashboard Controller. Thank you.

Upvotes: 0

Views: 719

Answers (2)

Jessica Fav
Jessica Fav

Reputation: 103

You can also try this out.

Controllers and models have a folder called concerns where you can keep codes that you want to be shared by different controllers and/or models.

Simply move the code that you want to share to the concerns folder, and then call them on each model.

You can define the code in the concerns folder using modules.

Upvotes: 1

Promise Preston
Promise Preston

Reputation: 29088

Finally, I got it to work.

I needed to implement service objects using Plain Old Ruby Objects. For each for the actions, I placed them in a separate service, and then called them in the controllers.

The steps are

  1. Create a folder under the app directory of the application named services.
  2. Create individual services for each of the controller actions.
  3. Call each service that you want on the controller.

That's all.

Upvotes: 0

Related Questions