计算逻辑应该放在Rails应用程序中的哪个位置?

时间:2009-11-07 03:53:37

标签: ruby-on-rails rails-activerecord helper

我有一个模拟房子的应用程序。 House has_many Rooms,Rooms has_many Lights和Small_appliances等。我还有一个名为Calculator的控制器,它是应用程序的访问方式。使用计算器控制器将数据添加到房屋(及其房间)。然后生成一个报告,该报告位于app / views / calculator / report.html.erb。

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

这是计算器控制器。

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

4 个答案:

答案 0 :(得分:5)

有几种方法可以接近它,但逻辑肯定不属于视图。如果我正确地阅读您的描述,您可以在清晰的层次结构中将各种模型相互关联,层次结构的顶部是House模型。在这种情况下,我会向House模型添加一组适当的方法方法,这些方法可能包括调用与给定House实例关联的Room模型中的计算方法以及关联线。通过这种方式,可以在每个级别执行相关计算,并通过在House模型级别组合一个或多个方法,您可以使用干净,富有表现力和可维护的方式来处理计算。

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

我会非常仔细地查看您想要的逻辑,看看它是如何被推入模型的,因为它可能属于它所属的位置,接近计算的实际数据,并且在特定于数据的类结构中;我不会创建一个模型来处理计算逻辑,除非你真的需要由于某种原因持久存储计算。

答案 1 :(得分:1)

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

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

您还可以在/ app / models /中创建纯红宝石对象。没有理由他们都必须继承ActiveRecord :: Base

答案 2 :(得分:1)

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

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

    如果业务逻辑非常简单并且仅在此Web应用程序后面使用,那么您可以将其放在app / models文件夹中。

    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是MyCoolClass的 instance__variable ,如果没有定义访问器方法,模板通常无法访问

答案 3 :(得分:0)

这完全取决于您正在创建的数据类型。计算器控制器是什么样的?

您可以在/ lib中创建自己的类并在模型中使用它们,这可以是将逻辑与控制器/帮助器分开的好方法。你有什么理由不能在模型中加入一些逻辑吗?