繁体   English   中英

Rails控制器变量混乱

[英]Rails controller variable mess

我有一个控制器,感觉实例变量太多。

控制器正在从各个地方提取数据,感觉真的很草率。 我已经看过一些Sandi Metz的演讲,看书和其他研究,并且我想有很好的练习,但是我只是不知道在这里做什么。

这种方法可以提取所有数据并将其发送到我的视图中,而且我可以使它正常工作,我只是知道这不是处理它的好方法,我希望有人可以指出一些代码示例,文档,视频或帮助我了解如何实现更好的样式。

我在SO和Google上进行了搜索,但大多数时候我发现有人在说要向视图发送哈希或JSON,因此我想在开始之前先知道这是否理想。

客户端,项目,人员,角色控制器和模型的代码确实非常相似,我正在努力将其重构为更干燥的形式。

例如,客户,项目,人员和角色财务控制器的控制器代码几乎与此完全相同。 :(

如果有帮助,我很乐意添加更多代码!

这是project_financials_controller#index

它几乎是从视图中获取数据,然后从数据库中提取一堆数据并将其发送到视图。 我目前仅使用索引方法,因为它只应该是“视图”,但是现在我们可以添加过滤器,例如时间,不同的客户等,因此我认为我需要以某种方式对其进行细分。

我确实有一个financial_reports_nav模型,可以调用它,我可以使用更多的模型,甚至可以制作一个financial_reports_controller来从适当的模型中提取数据,而我甚至不需要4个不同的控制器...

我完全欢迎任何意见/批评!

def index
  # CPPR = Client, Project, Person, Role
  @financial_type = 'project'
  @financial_params = params

  # This pulls the timeframe from the view and figures out the dates requested. (eg. "Last Week")
  @timeframe = Financial.time_frame(@financial_params[:timeframe], current_company.timezone, params[:start_date], params[:end_date])

  # This grabs all the data required to recall this financial report view at a later time
  @financial_nav = FinancialReportNav.set_financial_type(@current_user.id,@financial_type, @start_date, @end_date)

  # Grab all active and inactive people for client
  @people = Person.active.all
  @deleted_people = Person.inactive.all

  # This sends over all the info needed to generate the financial reports
  @project_financial_populate = Financial.new(@financial_params, @financial_type).populate_project_financials(current_company.default_hourly_cost, current_company.billing_rate, @timeframe[:start_date],@timeframe[:end_date])

  # This just pulls all the data from the database that the @project_financial_populate just populated (Can't we just use that??)
  @financial_rows = ProjectFinancial.all.map { |p| [ p.project_id, p.billable_hours, p.revenue,p.real_rate, p.hourly_expense, p.labor_expense_total, p.salary_expense,  p.gross_profit, p.profit_margin, p.missing_hourly_expense, p.missing_billable_rate ] }

  # Using the same view for CPPR's
  # Clients has an items count, so we just stuff everything into the first array slot
  @items = [1]

  # If these are not null then they show an option to change the financial filter type.
  @filter_by_client = Client.find_by('id = ?', @financial_params[:filter_by_client])
  @filter_by_project = Project.find_by('id = ?', @financial_params[:filter_by_project])
  @filter_by_person = Person.find_by('id = ?', @financial_params[:filter_by_person])
  @filter_by_role = PersonRole.find_by('id = ?', @financial_params[:filter_by_role])

  # This pulls a list of CPPR's that have tracked time in the requested timeframe
  @project_list = Financial.project_list(@timeframe[:start_date], @timeframe[:end_date])
  @client_list = Financial.client_list(@timeframe[:start_date], @timeframe[:end_date])
  @people_list = Financial.people_list(@timeframe[:start_date], @timeframe[:end_date])
end

每当发现至少有3个重复代码实例时,我总是倾向于将代码重构为DRY,但是我需要对新代码进行将来验证,以使其具有足够的灵活性以适应将来的可能更改。 但是,时间允许的话,所有这些都需要考虑。

鉴于您已有的代码并告诉了我的偏好,这就是我要做的:

  1. 模型继承
  2. 控制器继承
  3. 共用范本

路线

config / routes.rb

resources :client_financial
resources :project_financial
resources :person_financial
resources :role_financial

楷模

app / models / financial_record.rb

class FinancialRecord < ActiveRecord::Base # or ApplicationRecord if > Rails 5
  self.abstract_class = true

  # your shared "financials" model logic here
end

app / models / client_financial.rb

class ClientFinancial < FinancialRecord
  # override "financials" methods here if necessary
  # or, add new model specific methods / implementation
end

app / models / project_financial.rb

class ProjectFinancial < FinancialRecord
  # override "financials" methods here if necessary
  # or, add new model specific methods / implementation
end

app / models / person_financial.rb

class PersonFinancial < FinancialRecord
  # override "financials" methods here if necessary
  # or, add new model specific methods / implementation
end

app / models / role_financial.rb

class RoleFinancial < FinancialRecord
  # override "financials" methods here if necessary
  # or, add new model specific methods / implementation
end

控制器

app / controllers / financial_controller.rb

class FinancialController < ApplicationController
  before_action :set_instance_variables, only: :index

  protected

  def set_instance_variables
    # strips the last "Controller" substring and change to underscore: i.e. ProjectFinancialsController becomes project_financials
    @financial_type = controller_name[0..(-'Controller'.length - 1)].underscore

    # get the corresponding Model class
    model = @financial_type.camelcase.constantize
    # get the correspond Financial Model class
    financial_model = "#{@financial_type.camelcase}Financial".constantize

    @financial_params = params

    @timeframe = Financial.time_frame(@financial_params[:timeframe], current_company.timezone, params[:start_date], params[:end_date])

    # I dont know where you set @start_date and @end_date
    @financial_nav = FinancialReportNav.set_financial_type(@current_user.id,@financial_type, @start_date, @end_date)

    # renamed (or you can set this instance variable name dynamically)
    @records = model.active.all
    # renamed (or you can set this instance variable name dynamically)
    @deleted_records = model.inactive.all

    @financial_populate = Financial.new(@financial_params, @financial_type).populate_project_financials(current_company.default_hourly_cost, current_company.billing_rate, @timeframe[:start_date],@timeframe[:end_date])

    @financial_rows = financial_model.all.map { |p| [ p.project_id, p.billable_hours, p.revenue,p.real_rate, p.hourly_expense, p.labor_expense_total, p.salary_expense,  p.gross_profit, p.profit_margin, p.missing_hourly_expense, p.missing_billable_rate ] }

    @items = [1]

    @filter_by_client = Client.find_by('id = ?', @financial_params[:filter_by_client])
    @filter_by_project = Project.find_by('id = ?', @financial_params[:filter_by_project])
    @filter_by_person = Person.find_by('id = ?', @financial_params[:filter_by_person])
    @filter_by_role = PersonRole.find_by('id = ?', @financial_params[:filter_by_role])

    @project_list = Financial.project_list(@timeframe[:start_date], @timeframe[:end_date])
    @client_list = Financial.client_list(@timeframe[:start_date], @timeframe[:end_date])
    @people_list = Financial.people_list(@timeframe[:start_date], @timeframe[:end_date])
  end
end

app / controllers / client_financials_controller.rb

class ClientFinancialsController < FinancialController
  def index
    render template: 'financials/index'
  end
end

app / controllers / project_financials_controller.rb

class ProjectFinancialsController < FinancialController
  def index
    render template: 'financials/index'
  end
end

app / controllers / person_financials_controller.rb

class ProjectFinancialsController < FinancialController
  def index
    render template: 'financials/index'
  end
end

app / controllers / role_financials_controller.rb

class ProjectFinancialsController < FinancialController
  def index
    render template: 'financials/index'
  end
end

观看次数

app / views / financials / index.html.erb

<!-- YOUR SHARED "FINANCIALS" INDEX HTML HERE -->

PS这只是一个简单的重构。 在不了解项目的全部范围和未来计划的情况下,我将仅执行此操作。 话虽如此,我会考虑使用“ polymorpic”关联,然后只使用一个路由端点(即resources :financials ),然后传入诸如params[:financial_type]这样的参数过滤器,该过滤器已经直接映射了financial_type多态列名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM