Helper or model or controller?

Let's say I have a form_for with a select menu to assign a user to a belongs_to association:

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

      

I currently have @users in my controller like this:

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

      

I feel like this logic could be carried over to a helper or even a model. But I am confused as to where one can handle this and how.

+2


source to share


6 answers


The general answer depends on how often you intend to use it:

  • helper: Used frequently, but only in views or controllers.
  • model: used often wherever a model can be used (other models) Controller
  • : used rarely and only for certain actions.

However, in your case, the answer will not be one 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 it either exists in Rails Core or exists in gem form or a plugin.

What you are trying to do is already done and built into the Rails core. This is the ActionView :: Helpers :: FormOpitionsHelper method called collection_select

collection_select does exactly what you want to do, it is also much more robust than the single-target method.



It has the form

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

      

value_method and text_method are sent to each item in the collection to get the select value and display text for each select parameter. It is not required to have either 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 %>

      

+5


source


You should put this in the model as it is 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 this:

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

      

+1


source


This will be a model method since it has logic for the model. Helper methods should have UI level logic (whether to show a link or not) and HTML helpers (methods for creating links, for example)

0


source


I think going to the helper is the best thing as it just helps you create parameters for the select box, which is the UI layer.

But if you don't use this part of the code again, then it should go to the model! :)

0


source


Model:

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

      

View:

select :user_id, User.select_display

      

0


source


I had a similar problem and ended up using the module to stay as dry as possible (most of my models had a name and 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 simply extend the module:

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

      

On the controller, you can call Client.all_for_select. I usually do this on the before_filter file

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

  ...

  private
  def fill_selects
    @clients = Client.all_for_select
  end

      

0


source







All Articles