Formtastic select with grouping
Asked Answered
S

3

8

Now with Formtastic I have plain select:

= f.input :category, :as => :select, :include_blank => false, :collection => subcategories

Here I show only children categories. I use acts_as_tree plugin for parent-child relationship. I would like to show parent categories as well.

Formtastic generated select should look like this one:

<select name="favoritefood">
  <optgroup label="Dairy products">
    <option>Cheese</option>
    <option>Egg</option>
  </optgroup>
  <optgroup label="Vegetables">
    <option>Cabbage</option>
    <option>Lettuce</option>
    <option>Beans</option>
    <option>Onions</option>
  <option>Courgettes</option>
  </optgroup>
  ⋮
</select>

How to use grouping in Formtastic select for model with acts_as_tree functionality? Does anybody know?

UPDATED

I figured out that this should work:

= f.input :category, :include_blank => false, :group_by => :parent

but it doesn't with error:

undefined local variable or method `object_class' for #<Formtastic::SemanticFormBuilder:0x87d3158>

It looks like there is some bug in Formtastic. I have looked through formtastic.rb and found object_class in detect_group_association method:

  def detect_group_association(method, group_by)
    object_to_method_reflection = self.reflection_for(method)
    method_class = object_to_method_reflection.klass

    method_to_group_association = method_class.reflect_on_association(group_by)
    group_class = method_to_group_association.klass

    # This will return in the normal case
    return method.to_s.pluralize.to_sym if group_class.reflect_on_association(method.to_s.pluralize)

    # This is for belongs_to associations named differently than their class
    # form.input :parent, :group_by => :customer
    # eg. 
    # class Project
    #   belongs_to :parent, :class_name => 'Project', :foreign_key => 'parent_id'
    #   belongs_to :customer
    # end
    # class Customer
    #   has_many :projects
    # end
    group_method = method_class.to_s.underscore.pluralize.to_sym
    return group_method if group_class.reflect_on_association(group_method) # :projects

    # This is for has_many associations named differently than their class
    # eg. 
    # class Project
    #   belongs_to :parent, :class_name => 'Project', :foreign_key => 'parent_id'
    #   belongs_to :customer
    # end
    # class Customer
    #   has_many :tasks, :class_name => 'Project', :foreign_key => 'customer_id'
    # end
    possible_associations =  group_class.reflect_on_all_associations(:has_many).find_all{|assoc| assoc.klass == object_class}
    return possible_associations.first.name.to_sym if possible_associations.count == 1

    raise "Cannot infer group association for #{method} grouped by #{group_by}, there were #{possible_associations.empty? ? 'no' : possible_associations.size} possible associations. Please specify using :group_association"

  end

Indeed object_class undefined in this method and there is no privat method with that name in formtastic.rb. But we can use :group_association to define association explicitly.

- semantic_form_for ([:manager, @purchase_profile]) do |f|
  - f.inputs do
    = f.input :category, :include_blank => false, :group_by => :parent, :group_association => :children
  = f.buttons

but I ran into another error:

undefined method `children' for nil:NilClass

I tried swith off Acts_as_tree and write my own self-referenced assositions. The same as Acts_as_tree works should look like:

class Category < ActiveRecord::Base
  belongs_to :parent, :class_name => "Category", :foreign_key => "parent_id"
  has_many :children, :class_name => "Category", :foreign_key => "parent_id"
end

Error is the same. Can anybody help?

Updated

Next little step. This code without Formtastic works fine:

= grouped_collection_select('', :category_id, top_categories, :children, :name, :id, :name, :include_blank => true)

p.s: top_categories is helper method with collection of parent categories.

The last thing is translate it into Formtastic syntax :)

Shwalb answered 28/1, 2010 at 11:42 Comment(4)
Did you have any luck with getting this to work properly in Formtastic?Triptolemus
Not yet. I have submitted an issue to Formtastic guys at github. There is no spec coverage for grouped options and a failing spec will be appreciated.Shwalb
Did you figure this out?Blockbuster
@Michael Irwin: No, I switched to simple_form in my next project. DSL is almost the same, but more flexible. github.com/plataformatec/simple_formShwalb
C
17

In case anyone is having the same problem, you can do the following:

<%= f.input :category, :as => :select, :collection => option_groups_from_collection_for_select(ParentCategory.all, :categories, :name, :id, :name) %>

Reference from Rails API
Recommendation from Justin French (he mentions removing the :group_by)

Crinkleroot answered 4/8, 2012 at 21:55 Comment(8)
I have a problem with this that it doesn't auto-select the associated category. Have you encountered the same problem?Ensphere
FYI to others who come here via Google: to auto select associated category, just pass in the ID as a 6th parameter as per api.rubyonrails.org/classes/ActionView/Helpers/…Barony
@Barony i tried adding the :id as the 6th arugment, but to no avail. it auto selects the first option in the list.Polston
@Barony I have seen that option_groups_from_collection does not add selected="selected" for auto slection like grouped_collection_select() does. Have you experienced the same thing?Polston
@mak89k option_groups_from_collection_for_select works for me in a rails 3.2 app with Formtastic 2.2Barony
@Barony check this official deprecation link. I faced this problem while using DSL in Active Admin.Polston
@mak89k That link says you can still use regular rails helpers so I don't see how it applies. The issue might be that the ID you are supplying isn't valid. You can check the standard rails helper output by just doing this on a single page: <%= option_groups_from_collection_for_select(MasterCategory.all, :categories, :name, :id, :name, category_id) %>. This will let you see what is being sent to the formtastic input.Barony
BTW, ParentCategory.all doesn't belong in the view (check your MVC principles). Assign it to a variable in the controller.Samples
P
1

Hey, so I was trying to solve a particular problem with formtastic, and discovered that you can modify the query used to build the list by using :find_options. Looking at the code, I saw that if you don't specify :group_by, then the list of values ultimately comes down to a find(:all) on the model object (in a method called find_raw_collection_for_column in formtastic.rb). The parameters after the :all are the set of parameters specified by :find_options. Thus, you can apply any conditions or other parameters that you would normally use in find(*args) (see http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000333). Personally, I added this to my f.input statement:

:find_options => {:conditions => {:country_id => @business.country ? @business.country.id : nil}}

By doing this, I limited the select statement for the query to only the current county ID. But you should be able to use :group in a similar manner to specify who you wanted to GROUP BY in your query, like this:

:find_options => {:group => 'parent.id'}

Hopes this helps.

Peterkin answered 30/3, 2010 at 16:37 Comment(0)
O
0

Why not try building your list of items in a helper and then passing that into the select tag?

I don't know much about formtastic, or acts_as_tree, but if you are having problems getting it working how you have above, I think resorting to building your options before passing them to your select is perfectly reasonable.

Onfre answered 29/1, 2010 at 8:1 Comment(1)
This works as I updated my question. But I use Formtastic and would like to use it's syntax.Shwalb

© 2022 - 2024 — McMap. All rights reserved.