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

发布于 2024-08-10 03:31:33 字数 2292 浏览 3 评论 0原文

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

我的问题是报告的所有计算和逻辑应该放在哪里?目前我已经在视图中看到了所有内容,其中一些内容在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

I have an app that models a House. The House has_many Rooms, Rooms has_many Lights and Small_appliances, etc. I also have a controller called Calculator that is how the app is accessed. Data is added to the house (and its rooms) using the Calculator controller. Then a report is generated, which is located at app/views/calculator/report.html.erb.

My question is where should all the calculations and logic for the report go? Currently I have it all in the view, with some things in calculator_helper. Normally this would go in the model, right? But Calculator doesn't have a model that was generated. What is the standard for this?

Here is the calculator controller.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤星 2024-08-17 03:31:33

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

要做的一件事是确保数据库可以执行任何计算。例如,如果 Room 模型可以通过简单地查询它自己的数据来完成计算,那么无论如何都要使用 ActiveRecord 调用此类较低级别计算逻辑的能力将该计算负担推给数据库。有关详细信息,请查看 API 文档

我会非常仔细地查看您想要的逻辑,并了解如何将其推入模型中,因为这可能是它所属的位置,靠近计算的实际数据,并且位于专门表示该数据的类结构中;我不会创建一个模型只是为了处理计算逻辑,除非您确实需要出于某种原因持久存储计算。

There are a few ways to approach it, but the logic certainly does not belong in the view. You have the various models associated with one another in a clear hierarchy with the top of the hierarchy being the House model, if I am reading your description correctly. That being the case, I would add an appropriate method of set of methods to the House model that may be composed of calls to calculation methods in the Room models associated with a given House instance and on down the line of association. That ways the relevant calculation can be performed at each level and through composing one or more methods at the House model level you are able to have a clean, expressive and maintainable way to deal with calculations.

One thing to do, as well, would be to make sure that any calculations that can be performed by the DB are. For example, if there is a calculation that a Room model can do by simply querying it's own data then by all means push that computational burden to the DB using the ability of ActiveRecord to invoke such lower level calculation logic. Check out the API docs for the details.

I would look very carefully at the logic you want and see how it can be pushed into the model since that is probably where it belongs, close to the actual data of the calculations, and within the class structures that represent that data specifically; I would not create a model just to handle the calculation logic unless you really need to store the calculations persistently for some reason.

波浪屿的海角声 2024-08-17 03:31:33

我会在 RAILS_ROOT/lib/ 中创建一个名为 Calculator 的类,并将代码放入其中。

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

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

I would create a class in RAILS_ROOT/lib/ called, for example, Calculator and put the code in there.

Classes in /lib/ should be loaded an available anywhere in your app.

You can also create a plain ruby object in /app/models/. There's no reason they all have to inherit from ActiveRecord::Base

若水微香 2024-08-17 03:31:33

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

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

我之前的回答:

如果业务逻辑相当简单并且仅在该 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,并且通常无法在未定义访问器方法的情况下访问模板

Ok, now I can see the code posted. I can see the calculator_controller actually has no calculations in it, are they in the views?. Try this approach:

  1. Write a test that sets up an object which will return the results you need to return to the user of the web page, given a house, rooms or whatever else it needs.
  2. Build a model (in models) to make that test pass.
  3. Modify your controller code above to use your new calculator model
  4. Modify the tests of your controller so they also pass. These tests, of course, do not need to test any business logic.

My prior respose:

If the business logic is fairly simple and only used behind this web app, then you can put it in your app/models folder.

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

Then in your controller, create an instance of your model

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

Then in your templates you can access it

<%=h @mcc.calculate_coolness %>

Note that @other_things is an instance__variable of MyCoolClass and generally not accessible to the templates without accessor methods being defined

世界等同你 2024-08-17 03:31:33

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

您可以在 /lib 中创建自己的类并在模型中使用它们,这是将逻辑与控制器/帮助器分离的好方法。您无法将某些逻辑放入模型中是否有原因?

This all depends on what kind of data you're creating. What does the calculator controller look like?

You can create your own classes in /lib and use them in your models, which can be a good way to separate out logic from the controller/helpers. Is there a reason why you couldn't put some of the logic in the models?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文