I have a controller with two different actions, but both need this same code, which is a little long, how can I allow them access to this same behavior but keep it DRY?
@list = Contact.find :all,
:select => "companies.name AS co_name,
companies.id AS comp_id,
COUNT(contact_emails.id) AS email_count,
COUNT(contact_calls.id) AS call_count,
COUNT(contact_letters.id) AS letter_count,
COUNT(contact_postalcards.id) AS postalcard_count",
:conditions => ['contact_emails开发者_如何学运维.date_sent < ? and contact_emails.date_sent > ?',
report_end_date, report_start_date],
:joins => [
"LEFT JOIN companies ON companies.id = contacts.company_id",
"LEFT JOIN contact_emails ON contact_emails.contact_id = contacts.id",
"LEFT JOIN contact_letters ON contact_letters.contact_id = contacts.id",
"LEFT JOIN contact_postalcards ON contact_postalcards.contact_id = contacts.id",
"LEFT JOIN contact_calls ON contact_calls.contact_id = contacts.id"
],
#:group => "companies.id"
:group => "companies.name"
puts @list[0].attributes.inspect
You should move this code to model:
# Contatct model
def self.get_list(report_start_date, report_end_date)
self.find :all,
:select => "companies.name AS co_name,
companies.id AS comp_id,
COUNT(contact_emails.id) AS email_count,
COUNT(contact_calls.id) AS call_count,
COUNT(contact_letters.id) AS letter_count,
COUNT(contact_postalcards.id) AS postalcard_count",
:conditions => ['contact_emails.date_sent < ? and contact_emails.date_sent > ?',
report_end_date, report_start_date],
:joins => [
"LEFT JOIN companies ON companies.id = contacts.company_id",
"LEFT JOIN contact_emails ON contact_emails.contact_id = contacts.id",
"LEFT JOIN contact_letters ON contact_letters.contact_id = contacts.id",
"LEFT JOIN contact_postalcards ON contact_postalcards.contact_id = contacts.id",
"LEFT JOIN contact_calls ON contact_calls.contact_id = contacts.id"
],
#:group => "companies.id"
:group => "companies.name"
end
Then you can use it in controllers:
@list = Contact.get_list(report_start_date, report_end_date)
Probably you can also split it to smaller parts and use scopes and defined associations instead of writing all of it on your own.
I would add a function for generating the count and join sql:
class Contact < ActiveRecord::Base
def self.get_list(report_start_date, report_end_date)
all(:select => "companies.name AS co_name,
companies.id AS comp_id,
#{table_count_col(
:contact_emails,
:contact_calls,
:contact_letters,
:contact_postalcards
)}",
:conditions => ['contact_emails.date_sent < ? AND
contact_emails.date_sent > ?',
report_end_date, report_start_date],
:joins => join_table(
:companies,
:contact_emails,
:contact_letters,
:contact_postalcards,
:contact_calls
),
)
end
end
Where table_count_col
and table_join
are static methods inside Contact
class:
def self.table_count_col(*args)
args.collect do |table|
count_col = "#{table.to_s.gsub(/^contact_/, '').singularize}_count"
"COUNT(#{table}.id) AS #{count_col}"
end.join(",")
end
def self.table_join(*args)
args.collect do |table|
"LEFT JOIN #{table} ON #{table}.id = contacts.company_id"
end.join(",")
end
精彩评论