您如何确定必须将一行代码从控制器移动到模型?
我已经做过一些关于这个最佳实践的研究,这是迄今为止最好的解释,但我希望你们能够扩展这个,因为我的新手大脑无法完全理解它:)
编辑:假设我想在下面重构我的控制器:
class TaskController < ApplicationController
def index
@tasks = Task.find_all_by_complete(:false, :order => "created_at DESC")
end
end
到
class TaskController < ApplicationController
def index
@tasks = Task.find_incomplete
end
end
这2个代码块中的哪一个是正确的?
class Task < ActiveRecord::Base
def self.find_incomplete
find_all_by_complete(:false, :order => "created_at DESC")
end
end
或
class Task < ActiveRecord::Base
def find_incomplete
self.find_all_by_complete(:false, :order => "created_at DESC")
end
end
EDIT2:如果我想在下面重构我的控制器:
@average_review = @surf_school.surf_school_reviews.average(:rating).round(2)
到
@average_review = @surf_school.average_review
我在模型中的代码应该是:
def average_review
self.surf_school_reviews.average(:rating).round(2)
end
答案 0 :(得分:0)
通常作为起点,我会在模型中放置任何与CRUD相关的代码。在模型中设置自定义方法,以便您可以致电@user.invalidate
或@post.replace_owner(@user)
。 @user
的这些实例可以在模型中引用为self
。
例如:
class Post < ApplicationRecord
def add_owner(user)
self.update_attributes(user_id: user.id)
end
end
因此,将这样的逻辑移动到模型中可以实现更清晰的控制器代码。我还会处理请求,设置变量,使用模型方法并确定在Controller中加载哪个页面。
编辑:我也会使用第一个代码块:
def self.find_incomplete
find_all_by_complete(:false, :order => "created_at DESC")
end
正是如何手动创建ActiveRecord范围,该范围与以下内容相同:
class Task < ActiveRecord::Base
scope :find_complete -> { find_all_by_complete(:false, :order => "created_at DESC") }
end
但他们说这只是语法糖。你的第一个块就是我上面的块被转换成的东西,可以这么说。
有关ActiveRecord::Scoping的更多信息,请参阅
答案 1 :(得分:0)
在我的工作中,我们为模型层中的每个模型都有多个类。为简化起见,我们有一个DTO和DAO对象。 DTO包含字段,DAO包含保存,修改和删除数据库条目的方法。
我们的一些DAO还包含带有特殊/更复杂搜索查询的辅助方法,并覆盖标准保存方法,以防止控制器将无效数据输入到我们的模型中。
我们的控制器操作使用DAO将模型填充到某个点并将其新状态保存到数据库中。我们的控制器包含业务逻辑,但是一些DAO具有一些额外的方法来防止无效数据进入数据库。它使业务逻辑更易读,更容易理解。
另外要记住的是,如果您遵循某种做法,它是完美的,但如果它不符合您的要求,请考虑侧身。就像,如果您碰巧在每次保存操作之前必须执行必须执行的业务逻辑,我老实说要么定义一个实用程序/帮助程序类,它具有保存此逻辑的静态方法或覆盖模型对象的save方法并把它移到那里。
注意:DAO代表数据访问对象。这在我们的用例中很常见,但是您只有一个基本上相同但没有多个类的类。这是在我开始在这里工作之前选择的设计模式。
编辑:我要去第二个选项。但是这篇文章可能会对你有所帮助:What does def `self.function` name mean?