Cameron
Cameron

Reputation: 4211

Helper method or Model or Controller?

Say I have a form_for with a select menu to assign a User on a belongs_to association:

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

Currently I have @users in the controller as follows:

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

I feel like this logic should maybe moved into a helper or even to the model. But I am confused as to where to deal with this and how.

Upvotes: 2

Views: 1692

Answers (6)

kikito
kikito

Reputation: 52698

I had a similar problem and ended up using a module, in order to stay as DRY as possible (most of my models had a name and an id)

The module looked like this:

#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

On your model, you just extend the module:

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

On your controller, you can call Client.all_for_select. I usually do this on a before_filter

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

  ...

  private
  def fill_selects
    @clients = Client.all_for_select
  end

Upvotes: 0

Ryan Bigg
Ryan Bigg

Reputation: 107738

The model:

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

The view:

select :user_id, User.select_display

Upvotes: 0

EmFi
EmFi

Reputation: 23450

The general answer depends on how often you're going to use it:

  • helper: used often but only in views or controllers
  • model: used often anywhere the model can be used (other models)
  • controller: used rarely and only for specific actions.

However in your case, the answer is none of the above, and stop trying to reinvent the wheel. About 95% of the things people try to do with Rails are tasks that others have already done. There's a very good chance that it's either in the Rails Core or exist in either gem or plugin form.

What you're trying to do has already been done, and is built into the Rails core. It's a ActionView::Helpers::FormOpitionsHelper method called collection_select

collection_select does exactly what you want to do, it's also much more robust than a single purpose method.

It has the form of

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

value_method and text_method are sent to each item in collection to get the select value and the display text for each select option. It is not required that either are column names.

Use it like this:

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

Upvotes: 5

Mike
Mike

Reputation: 5193

You should put this in a model as it's logic oriented and by the way you should never do

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

but

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

and if full_name is a method, something like that :

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

Upvotes: 1

paolo granada lim
paolo granada lim

Reputation: 504

i think moving that to a helper is the best thing, since it just does help you with creating options for a select box, which is UI level.

But unless you would use that piece of code again, then to the model it must go! :)

Upvotes: 0

Jim Deville
Jim Deville

Reputation: 10672

That would be a model method since it has logic for the model. Helper methods should have UI level logic (whether to display a link or not) and HTML helpers (methods to generate links for example)

Upvotes: 0

Related Questions