Rails在控制器中使用实例变量或在帮助器中生成?

时间:2018-05-03 20:20:59

标签: ruby-on-rails

所以我试图在发票页面上建立past_due_amount,我试图只查找当前帐户的发票,这些发票没有付清,应该是过去的。

我粗略地说:

past_due_amount = Invoice.where(account: invoice.account, status: :unpaid).where('date < ? ', invoice.date).map(&:due).sum

有关其他背景,请参阅以下模型:

发票:

class Invoice < ApplicationRecord
 belongs_to :account

 has_many :line_items, dependent: :destroy
 has_many :payment_destinations, dependent: :destroy
 has_many :prorated_fees, dependent: :nullify

 enum status: [:unpaid, :paid]

 validates :date, presence: true
 validates :period_start, :period_end,
   uniqueness: { scope: :account, allow_blank: true }, on: :create
 validate :start_is_before_end

 DAYS_DUE_AFTER_DATE = 14.days

 scope :descending, -> { order(date: :desc) }
 scope :ascending, -> { order(date: :asc) }
 scope :due, -> { unpaid.where(arel_table[:date].lteq(Time.zone.today - DAYS_DUE_AFTER_DATE)) }

 def total
  if persisted?
    line_items.sum(:amount)
  else
    line_items.map(&:amount).sum
  end

端     端

帐户:

 class Account < ApplicationRecord
 belongs_to :customer
 belongs_to :property_address,
   class_name: Address.to_s,
   dependent: :destroy,
   required: false

 [:products, :account_changes, :equipments,
  :payments, :invoices].each do |assoc|
   has_many assoc, dependent: :destroy
 end

 accepts_nested_attributes_for :property_address
 delegate :street, :city, :state, :zip,
   to: :property_address, allow_nil: true
 delegate :email, :full_name, to: :customer

 enum status: [:staged, :active, :inactive]

 scope :active_or_staged, -> { where(status: [:staged, :active]) }
 scope :past_due, lambda {
   joins(:invoices)
     .where(
       Invoice.arel_table[:status].eq(:unpaid)
       .and(Invoice.arel_table[:date].lt(Time.zone.today - 14.days))
     ).distinct
 }

 scope :search, lambda { |term|
   joins(:customer)
     .where(
       arel_table[:account_num].matches("%#{term}%")
       .or(Customer.arel_search(term))
     )
 }
end

随着粗略的代码到位,我决定在show方法中的InvoicesController上构建一个实例变量,如下所示:

 def show
  @invoice = Invoice.find_by!(id: params[:id], account: current_customer.account_ids)
  @account = @invoice.account
  @past_due_amount = Invoice.where(account: @account, status: :unpaid).where('date < ?', @invoice.date).map(&:due).sum
 end

没有出现任何错误,但由于我的例子充其量只是很差,所以没有说太多。但我的问题是......我真的应该把它放在帮助器而不是InvoicesController甚至模型中的show方法吗?

编辑:

我也试过加入我的发票模型:

def self.past_due_amount
 Invoice.where(account: @account, status: :unpaid).where('date < ?', @invoice.date).map(&:due).sum
end

然后在我的InvoicesController中:

def show
 @invoice = Invoice.find_by!(id: params[:id], account: current_customer.account_ids)
 @account = @invoice.account
 @past_due_amount = Invoice.past_due_amount
end 

最终得到未定义的方法`date&#39;为@ invoice.date。

3 个答案:

答案 0 :(得分:1)

最好的方法是在past_due_amount

中创建方法InvoicesHelper
module InvoicesHelper

  def past_due_amount
    Invoice.where(account: @account, status: :unpaid).where('date  <?', @invoice.date).map(&:due).sum
   end
end

在你的控制器中只需初始化所有实例变量

def show
 @invoice = Invoice.find_by!(id: params[:id], account: current_customer.account_ids)
 @account = @invoice.account
end 

在视图中,您应该使用:<%= past_due_amount >来显示您的数据

答案 1 :(得分:1)

Account模型

中创建实例方法
def past_due_amount
  invoices.map(&:due).sum
end

然后从视图中你可以全部@account.past_due_amount。无需在控制器操作中创建额外的实例变量

答案 2 :(得分:0)

所以我有点使用帕特里克的答案,但实际上却失败了所以我转而将发票作为params。

辅助

module InvoicesHelper
 def past_due_amount(invoice)
  Invoice.where(account: invoice.account, status: :unpaid).where('date < ?', invoice.date).map(&:due).sum
 end
end

然后在我看来:

<% if past_due_amount(invoice).positive? %>
 <p><%= number_to_currency past_due_amount(invoice) %></p>
<% end %>