计算逻辑应该放到Rails应用程序中去哪里?

问题描述:

我有一个模拟房子的应用程序。房子has_many房间,房间has_many灯和small_appliances等,我也有一个名为计算器控制器是如何访问该应用程序。使用计算器控制器将数据添加到房屋(及其房间)。然后生成一个报告,位于app/views/calculator/report.html.erb。计算逻辑应该放到Rails应用程序中去哪里?

我的问题是,报告的所有计算和逻辑都应该放在哪里?目前我在视图中都有,在calculator_helper中有一些东西。通常这会在模型中进行,对吧?但计算器没有生成的模型。这是什么标准?

这里是计算器控制器。

class CalculatorController < ApplicationController 
    def index 
    end 

    def save_house 
    @house = House.new(params[:house]) 
    respond_to do |format| 
     if @house.save 
     format.html { render :action => 'add_rooms', :id => @house } 
     format.xml { render :xml => @house, :status => :created, :location => @house } 
     else 
     format.html { render :action => 'index' } 
     format.xml { render :xml => @house.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    def add_rooms 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 

    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding rooms" 
    redirect_to :action => 'index' 
    end 

    def add_room 
    @room = Room.new(params[:room]) 
    @house = @room.house 

    respond_to do |format| 
     if @room.save 
     flash[:notice] = "Room \"#{@room.name}\" was successfully added." 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room, :status => :created, :location => @room } 
     else 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room.errors, :status => :unprocessable_entity } 
     end 
    end 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding a room" 
    redirect_to :action => 'index' 
    end 

    def report 
    flash[:notice] = nil 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before generating a report" 
    redirect_to :action => 'index' 
    end 
end 
+0

请向我们展示您的计算器类。 – 2009-11-07 06:27:12

+0

我喜欢James的回答。我想你应该问自己的另一个问题就是为什么你要突破常规 - 计算器控制器为什么要处理似乎属于控制器的东西?我不是说你做错了,我只是说这是值得多加思考的。 – 2009-11-07 08:38:21

+0

好点,安迪。 Ryan,在你开始担心控制器和视图之前,先获取MODELS。使用这种方法,您可能会发现所有计算的正确位置是House模型。 – 2009-11-07 16:11:14

这一切都取决于您创建的数据类型。计算器控制器是什么样的?

您可以在/ lib中创建自己的类并在模型中使用它们,这可以很好地将逻辑从控制器/帮助程序中分离出来。你有没有理由不能在模型中加入一些逻辑?

+0

calculator_controller保存数据并将用户移动到允许他们输入更多信息的下一页。 模型正在验证,但就是这样。正在执行的计算主要是基于房屋和房间参数的数字计算。 我试着制作一个计算器的模型,但后来我无法从视图中访问这些变量。我需要做出所有的全局变量吗? – Ryan 2009-11-07 04:08:36

我会在RAILS_ROOT/lib/called中创建一个类,例如Calculator,并将代码放在那里。

/lib /中的类应该在应用程序中的任何位置加载。

您还可以在/ app/models /中创建一个普通的ruby对象。没有理由他们都必须继承ActiveRecord :: Base

+0

我已经在应用程序/模型中创建了一个不能从ActiveRecord继承的calculator.rb文件。但是,当我将代码移到该文件时,我无法再从视图中访问它。我假设这是因为我用局部变量做了所有事情。解决这个问题的最好方法是什么?我尝试将它们更改为全局变量,但似乎没有帮助。 – Ryan 2009-11-07 04:47:12

+0

将方法放入模型中而不是lib /中的类可以更好地将逻辑与基础数据关联。另外,它具有明显的优点,即不会遇到与实例变量有关的问题,因为您可以调用已在控制器和视图中处理的模型实例上的方法。 如果在代码库中使用多个类,比如Mixin模块,或者您正在重构为可重用的边车项目/插件,则将代码编入到lib /中是最有意义的。如果逻辑是代码库的一部分,请将其保存在主代码中。 – 2009-11-08 00:12:40

有几种方法来处理它,但逻辑肯定不属于视图。如果我正确地阅读了你的描述,你就可以将各种模型与层次结构的顶层作为House模型进行清晰的层次关联。既然如此,我会为House模型添加一套合适的方法,这些方法可能由与给定House实例关联的房间模型中的计算方法调用以及关联关系组成。通过这种方式,可以在每个级别执行相关计算,并且通过在众议院模型级别组合一种或多种方法,您可以拥有清晰,富有表现力且可维护的方式来处理计算。

要做的一件事就是确保任何可以由数据库执行的计算。例如,如果有一个房间模型可以通过简单地查询它自己的数据来进行计算,那么通过所有的方式,使用ActiveRecord调用这样的较低级别计算逻辑的能力来将该计算负担推送到数据库。详情请查看API docs

我会仔细看看你想要的逻辑,看看它是如何被推入模型的,因为这可能是它属于的地方,靠近计算的实际数据,并且在表示该数据的类结构中特别;我不会创建一个模型来处理计算逻辑,除非您真的需要持续存储计算出于某种原因。

好的,现在我可以看到发布的代码。我可以看到calculator_controller实际上没有计算它们,它们在视图中吗?试试这个办法:

  1. 写一个测试,给出了一套房子,房间或其他任何需要设置的对象将返回您需要返回到该网页的用户的结果。
  2. 建立一个模型(在模型中)使测试通过。
  3. 修改上面的控制器代码以使用您的新计算器模型
  4. 修改您的控制器的测试,以便它们也通过。这些测试当然不需要测试任何业务逻辑。

我之前respose:

如果业务逻辑相当简单,只用这背后的Web应用程序,那么你可以把它放在你的应用程序/模型文件夹中。

class MyCoolClass 
    def initialize(clues) 
    @other_things = OtherThing.all 
    end 
    def do_cool_thing; end 
    def calculate_coolness 
    @other_things.length 
    end 
end 

然后在你的控制器,创建模型的实例

def index 
    @mcc = MyCoolClass "A clue as to what I want" 
    render 
end 

然后在你的模板,您可以访问它

<%=h @mcc.calculate_coolness %> 

注意@other_things是一个instance__variable MyCoolClass并且通常无法在没有定义访问器方法的情况下访问模板

+0

当逻辑开始混淆AR模型时,我喜欢建立这样的模型。 – 2009-11-07 16:12:06