Лучший способ реорганизовать приложение Rails с помощью Rubocop

Я работаю над приложением для получения стипендии, где люди могут делать пожертвования в поддержку различных программ, в которых они хотят участвовать. Мне нужна помощь с рефакторингом Rubocop в рельсах.

У меня есть следующие проблемы;

  1. Действие контроллера вызывает только один метод модели, кроме начального поиска или нового. Сделайте в модели кастомные методы .new или .update со всем необходимым.
  2. Слишком большой размер условия ветки назначения для индекса
  3. В методе слишком много строк

Я пытался реорганизовать код, но все еще сталкиваюсь с теми же проблемами с кодом.

Мои коды;

Контроллер панели мониторинга (начальный*)

class DashboardController < ApplicationController
  def index
    #Paid Donations in Chart
    @paid_donations = Donation.where(payment: true).count
    #Unpaid Donations in Chart
    @unpaid_donations = Donation.where(payment: false).count
    #Total Donations Sum
    @total_donations_sum = Donation.where(payment: true).sum(:amount)
    #Deployed Donations
    @deployed_donations = Donation.where(deployment: true).sum(:amount)
    #Not Deployed Donations
    @not_deployed_donations = Donation.where(deployment: false,  payment: true).sum(:amount)
    #Deployed Donations Percentage
    @deployed_donations_percentage = (@deployed_donations.to_f / @total_donations_sum.to_f) * 100
    #Not Deployed Donations Percentage
    @not_deployed_donations_percentage = (@not_deployed_donations.to_f / @total_donations_sum.to_f) * 100

    #Total Donations
    @total_donations = Donation.count
    #Paid Donations
    @paid_donations = Donation.where(payment: true).count
    #Unpaid Donations
    @unpaid_donations = Donation.where(payment: false).count

    #All Programs
    @programs = Program.all
  end
end

Контроллер панели мониторинга (рефакторинг)

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_percentage = percentage(@deployed_donations, @total_donations_sum)
    # Not Deployed Donations Percentage
    @not_deployed_donations_percentage = (@not_deployed_donations.to_f / @total_donations_sum.to_f) * 100

    # Total Donations
    @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

Модель пожертвования (начальная)

class Donation < ApplicationRecord
  belongs_to :program
end

Модель пожертвований (рефакторинг)

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 :paid_sum, -> { where(payment: true).sum(:amount) }
  scope :deployed_sum, -> { where(deployment: true).sum(:amount) }
  scope :not_deployed_sum, -> { where(deployment: false).sum(:amount) }

  def percentage(donate, total)
    (donate.to_f / total.to_f) * 100
  end
end

Мне нужна помощь по передовым методам работы с рельсами для решения этих проблем, следуя принципу тощих моделей и тощих контроллеров рельсов.


person Promise Preston    schedule 11.06.2019    source источник


Ответы (1)


Я думаю, в этом случае вы можете создать метод в модели Donation, чтобы вернуть все значение для отображения в 1 хеше.

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).sum(:amount) }

  def self.deployed_donations_percentage
    (deployed_sum / size) * 100
  end

  def self.not_deployed_donations_percentage
    (not_deployed_sum / size) * 100
  end

  def self.info
    {}.tap do |info|
      info[:paid_donations] = paid_count
      info[:unpaid_donations] = unpaid_count
      info[:total_donations_sum] = paid_count
      info[:deployed_donations_percentage] = deployed_donations_percentage
      info[:not_deployed_donations_percentage] = not_deployed_donations_percentage
      #...anything you want to show
    end

  end
end

в вашем контроллере

class DashboardController < ApplicationController    
  def index
    # donations info
    @donations_info = Donation.info
    # All Programs
    @programs = Program.all
  end
end

и, по вашему мнению, вы можете получить доступ к значению с помощью

<%= @donations_info[:paid_donations] %>
person Văn Trọng Trần    schedule 12.06.2019
comment
Это так круто. Приношу свои извинения, что не ответила достаточно рано, я не получила уведомление заранее. Как мне также реорганизовать эти другие элементы на контроллере? Процент # развернутых пожертвований @deployed_donations_percentage = percentage(@deployed_donations, @total_donations_sum), Процент # неразвернутых пожертвований @not_deployed_donations_percentage = (@not_deployed_donations.to_f / @total_donations_sum.to_f) * 100. Я использовал def percentage(donate, total) (donate.to_f / total.to_f) * 100 end на модели, но не знаю, как реализовать на контроллере - person Promise Preston; 13.06.2019
comment
@PromisePreston, добро пожаловать, я обновил свой ответ - person Văn Trọng Trần; 14.06.2019
comment
Большое спасибо. Я только что заметил, что вы использовали def self.deployed_donations_percentage (deployed_sum / size) * 100 end. Я понимаю, что использование self.a_method во время определения метода делает метод методом класса, но я хочу спросить, почему вам нужно было использовать метод класса, а не просто метод экземпляра, а затем вызывать метод на контроллер. Кроме того, я хотел бы знать, почему вы использовали размер, потому что я действительно не понимаю его наилучшего использования (когда и как использовать метод .size). Пожалуйста, потерпите меня. Моих вопросов кажется много. Я еще не эксперт в рубине на рельсах. Спасибо. - person Promise Preston; 14.06.2019
comment
@PromisePreston использует метод класса, когда нас не волнует значение объекта или экземпляра. Вы можете видеть, что deployed_sum и size не являются атрибутами какого-либо экземпляра, а также deployed_donations_percentage, так что это метод класса. - count выполнит SQL-запрос COUNT - length рассчитает длину результирующего массива - size попытается выбрать наиболее подходящий из двух, чтобы избежать чрезмерных запросов - person Văn Trọng Trần; 16.06.2019
comment
Спасибо, Ваня, за подробное объяснение. Я опробовал ваше решение, но, похоже, столкнулся с препятствием. Когда я пытаюсь просмотреть панель инструментов, информация о пожертвованиях не отображается. Я думаю, причина в том, что мы переместили бизнес-логику в Модель пожертвований, а затем мы вызываем всю эту логику в Контроллер панели управления, который, похоже, не может получить доступ к данным из Модели пожертвований. Пожалуйста, как мне представить бизнес-логику, которую мы определили в модели пожертвований, для контроллера информационной панели, поскольку это разные контроллеры и модели? Спасибо. - person Promise Preston; 17.06.2019
comment
@PromisePreston здесь не видно: stackoverflow .com/questions/18563229/, если это все еще не работает, можете ли вы показать мне свой код? - person Văn Trọng Trần; 18.06.2019
comment
Спасибо за поддержку. Я кое-что прочитал об Service Objects по ссылке, которой вы поделились. Он советует мне переместить бизнес-логику из модели в папку служб, а затем выполнить вызов из каждой службы, которую я хочу, к контроллеру. Я все еще не уверен, как реализовать это в приведенном ниже коде. Если вы можете помочь с этим, я буду очень признателен, а затем узнаю, как реализовать это на этом примере. Большое спасибо - person Promise Preston; 18.06.2019