Sylar
Sylar

Reputation: 12072

Removing an anti-pattern from views to controller

I have two models with a relation:

Company has_many :quotes

I want to remove an anti-pattern logic and place it in the controller:

<%= Quote.where(company_id: c.id).where(paid: true).count %>

The setup:

Controller:

@companies = Company.all

Views:

<% @companies.each do |c| %>
  <%= Quote.where(company_id: c.id).where(paid: true).count %>
<% end %>

I want to show total quotes for each company. While the above works, I do not want that logic in the views. How to put that in the controller?

I have this in controller:

...

@jobs_count = @companies.map do |c| Quote.where(company_id: c.id).where(paid:true) end

...

That does not work. The view page does not use params.

Upvotes: 1

Views: 51

Answers (2)

Bobby Matson
Bobby Matson

Reputation: 1488

PJSCopeland has made a great suggestion by using a named scope:

class Quote
  scope :paid, -> { where paid: true }
end

but I would suggest taking it a step further by keeping "quotes paid count" as a concern of your Company model:

class Company
  def quote_count
    quotes.paid.count
  end
end

Then in your view:

<% @companies.each do |c| %>
  <%= c.quote_count %>
<% end %>

This also makes it easier to unit test you Quote and Company models.

Upvotes: 1

PJSCopeland
PJSCopeland

Reputation: 3006

Company.has_many :quotes already allows you to use company.quotes rather than Quote.where(company_id: company.id).

Now, define this scope on the Quote model:

class Quote
  scope :paid, -> { where paid: true }
  # ...
end

Now your view can say

<% @companies.each do |c| %>
  <%= c.quotes.paid.count %>
<% end %>

... with no need for any changes in the controller.

Does that look better?

Upvotes: 3

Related Questions