在我的 Rails 应用程序中创建新文章时,我需要一些下拉菜单的Users
和Categories
列表,以便我可以为文章选择类别和作者。
目前我在控制器中执行此操作:
def new
@article = Article.new
@categories = Category.order('title asc').collect { |t| [t.title, t.id] }
@users = User.order('email asc').collect { |t| [t.email, t.id] }
end
然后在视图中:
<%= f.select :category_id, options_for_select(@categories), :prompt => '-- Please Select --', :required => true %>
但是根据 RubyDocs 的说法,这是一种不好的做法,而且它不是很干燥,因为我也必须为编辑方法执行此操作。为了防止这种情况,我能想到两种可能的选择:
1.) 使用这样的帮助程序:
def users_for_select
User.order('email asc').collect { |t| [t.email, t.id] }
end
def categories_for_select
Category.order('title asc').collect { |t| [t.title, t.id] }
end
然后在视图中:
<%= f.select :category_id, options_for_select(categories_for_select), :prompt => '-- Please Select --', :required => true %>
2.) 将其移动到模型:
def self.categories_for_select
Category.order('title asc').collect { |t| [t.title, t.id] }
end
def self.users_for_select
User.order('email asc').collect { |t| [t.email, t.id] }
end
然后在控制器中执行以下操作:
def new
@article = Article.new
@categories = Category.categories_for_select
@users = User.users_for_select
end
选项 1 感觉更干净,因为它从控制器中删除了代码,但我的印象是选项 2 会更好,因为它使用数据模型(按预期)并且控制器仍在发送数据(再次按预期)但更 DRY。
我觉得帮助程序和模型之间有时在获取数据方面存在一些重叠。
我现在会使用 (1) 您的助手方法。它简单明了。正如我在评论中所说,如果您对选项 (2) 很感兴趣,您可以在模型周围使用装饰器(例如使用 draper)来添加我认为非常特定于视图的逻辑。
关于帮助程序方法的一个说明 - 使用 pluck
而不是 collect
,这样您就不会选择列或实例化一堆不需要的对象。
此外,order
默认为 asc
,因此您可以将整个内容缩短为:
def users_for_select
User.order(:email).pluck(:email, :id)
end
我会为此使用一个辅助方法:
# in a helper
def category_options_for_select
options_for_select(Category.order(:title).pluck(:title, :id))
end
# in the view
<%= f.select :category_id, category_options_for_select, prompt: '-- Please Select --', required: true %>
我个人会选择选项 1。
当然,你可以把它放在你的模型中。您迟早会发现这将是使模型膨胀的好方法。然后,您可能会考虑使用担忧来隐藏膨胀。混乱的趋势仍在继续。
这就是为什么我认为选项 1 更好。即使您没有创建单独的类来处理格式设置,您仍然将功能抽象到更易于扩展的较小段中。当然,作曲胜过继承。
Bryany的这篇很棒的帖子为耐火脂肪模型提供了很好的选择。
正如@damien在他的回答中已经指出的那样,您需要使用ActiveRecord的pluck
而不是ruby的collect
。 Pluck
查询数据库,以便它只返回您需要的对象。