辅助方法或模型或控制器?

时间:2009-10-26 23:05:03

标签: ruby-on-rails model-view-controller

假设我有一个带有选择菜单的form_for,用于在belongs_to关联上分配用户:

...
form.select :user_id, @users, :prompt => "Select a User"
...

目前我在控制器中有@users如下:

@users = User.all.map { |u| [u.full_name, u.id] }

我觉得这个逻辑可能会转移到帮助者甚至模型中。 但我很困惑在哪里处理这个以及如何处理。

6 个答案:

答案 0 :(得分:5)

一般答案取决于您使用它的频率:

  • helper:经常使用但仅在视图或控制器中使用
  • 模型:经常用于可以使用模型的任何地方(其他模型)
  • 控制器:很少使用,仅用于特定操作。

但是在你的情况下,答案不是上述情况,而是停止尝试重新发明轮子。人们尝试使用Rails的事情中,大约95%是其他人已经完成的任务。它很可能是在Rails Core中,或者以gem或plugin形式存在。

您尝试做的事情已经完成,并且内置于Rails核心。它是一个名为collection_select

的ActionView :: Helpers :: FormOpitionsHelper方法

collection_select正是你想要做的,它也比单一目的方法更强大。

它具有

的形式
collection_select(object, method, collection, value_method,
  text_method, select_options = {}, html_options)

value_method和text_method发送到集合中的每个项目,以获取每个选择选项的选择值和显示文本。不要求列名都是。

像这样使用:

<% form_for @whatever do |form| %>
  <%= form.collection_select :user_id, User.all, :id,
    :full_name, :prompt => "Select a User" %>
<% end %>

答案 1 :(得分:1)

你应该把它放在一个模型中,因为它是面向逻辑的,你应该永远不会这样做

@users = User.all.map { |u| [u.full_name, u.id] }

但是

@users = User.all(:select => "full_name, id")

如果full_name是一个方法,那就是:

@users = User.all(:select => "last_name, first_name, id").map{|u| [User.full_name(u.first_name, u.last_name), u.id]}

答案 2 :(得分:0)

这将是一种模型方法,因为它具有模型的逻辑。 Helper方法应该具有UI级逻辑(是否显示链接)和HTML帮助程序(例如,生成链接的方法)

答案 3 :(得分:0)

我认为将其转移到助手是最好的事情,因为它只是帮助您为选择框创建选项,这是UI级别。

但除非你再次使用那段代码,否则它必须去模型! :)

答案 4 :(得分:0)

模特:

def self.select_display
  all(:select => "id, first_name, last_name").map { |u| [u.name, u.id] }
end

观点:

select :user_id, User.select_display

答案 5 :(得分:0)

我遇到了类似的问题并最终使用了一个模块,以便尽可能保持DRY(我的大多数模特都有一个名字和一个id)

模块看起来像这样:

#lib/all_for_select.rb
module AllForSelect

  def all_for_select(permission = :read)
    #used declarative authorization for checking permissions
    #replace first line with self.find(:all, if not using it
    with_permissions_to(permission).find( :all,
      :select =>"#{table_name}.id, #{table_name}.name",
      :order => "#{table_name}.name ASC"
    )
  end

end

在您的模型上,您只需扩展模块:

class Client < ActiveRecord::Base
  extend AllForSelect
  ...
end

在您的控制器上,您可以调用Client.all_for_select。我通常在before_filter上执行此操作

class SalesController < ApplicationController
  before_filter :fill_selects, :only => [:new, :edit, :update, :create]

  ...

  private
  def fill_selects
    @clients = Client.all_for_select
  end