0

I am building a website that is basically a small Content Management System. (in the sense that the user will be able to dynamicaly change most content of the site)

In my rails app I have two models, a Category and a Subcategory. A Category has many Subcategories, and a Subcategory belongs to a Category.

Each subcategory has a position field, which dictates where it is displayed under the category.

When creating a subcategory by form, I want the user to have the option to select the category from a list of all categories in the database (Which I have working fine). I then want the position field (a dropdown box) to update based on what positions are currently available within that category.

My current idea to track the available position for subcategory in my Application Controller is:

def subcategory_count(subcategory)
category = subcategory.category
@count = category.subcategories.count
end 

I then add +1 to @count so it gives me the available positions, +1. (If anyone has a better way of doing this, please let me know.)

I am currently following Ryan Bates' railscasts 88 revised which is dynamic select menus revised. Here is what my form looks like right now.

<%= form_for(@subcategory) do |f| %>
<p>
<%= f.label(:name) %>
<%= f.text_field :name %>
</p>
<p>

<%= f.label(:category_id) %>  
<%= f.collection_select :category_id, Category.order(:position), :id, :name,     include_blank: true %>

</p>

<p>
<%= f.label :position, "Position" %>
<%= f.grouped_collection_select :position, Category.order(:position), :subcategories,  :name, :position, :position%>
</p>
<p>


<%= f.submit("Submit") %>
</p>
<% end %>

The problem with this code is that I need it to display as an int so I can add +1 to it, otherwise when there are no subcategories in the database it just shows blank and doesn't allow me to pick the "1" position.

So, I need to find a way to update the field to show the available positions in the category, but I don't know how to do that exactly. Any help will be greatly appreciated.

Verbeia
  • 4,400
  • 2
  • 23
  • 44
ruevaughn
  • 1,319
  • 1
  • 17
  • 48

1 Answers1

1

There are different solutions to your problem.

If continue use your AJAX-less solution, try to override or just create different method on Category to return existing subcategories plus one new (for stub purpose only):

class Category
has_many :subcategories

def subcategories_with_placeholder
  result = [Subcategory.new :position => (subcategories.length + 1)]
  subcategories.each{|s| result << s}
  result
end
#other class code
end

And replace

<%= f.grouped_collection_select :position, 
  Category.order(:position), 
  :subcategories,
  :name, 
  :position, 
  :position%>

With:

<%= f.grouped_collection_select :position, 
  Category.order(:position), 
  :subcategories_with_placeholder,  
  :name, 
  :position, 
  :position%>
Mark Huk
  • 2,379
  • 21
  • 28
  • Thanks for the answer @Mark, it makes sense. I am also curious about the Ajax solution. I plan on using ajax to update my forms but I don't know how I would use it to get the correct value of position. I tried to implement your fix into my code and now I am getting the error `code` undefined method `position' for {:position=>1}:Hash Extracted source (around line #15): 12: 13:

    14: <%= f.label :position, "Position" %> 15: <%= f.grouped_collection_select :position, Category.order(:position), :subcategories_with_placeholder, :name, :position, :position%> 16:

    17:

    18:

    – ruevaughn Feb 12 '12 at 02:24
  • Here is what I ended up putting in my category.rb model `def subcategories_with_placeholder result = [Subcategory.new, position: (Subcategory.count + 1)] subcategories.each{|s| result << s} result end` – ruevaughn Feb 12 '12 at 02:29
  • Seems like you have error in your code: line `[Subcategory.new, position: (Subcategory.count + 1)]` intend to create an array with one Subcategory instance that have position +1 of the current `Category`'s subcategories count. But your code seems like simply adds two items into array: One empty Subcategory and second - hash, that might cause error that you provided in first coment. – Mark Huk Feb 12 '12 at 08:42
  • Thanks again, so I think my biggest problem is I may not be understanding what the subcategories_with_placeholder function is doing. When it returns result, what is it returning exactly? It seems to me like the line `subcategories.each{|s| result << s}` loops through every subcategory and stores it in the result array? How does that get me the 'position' that I need? Thanks again for your help. – ruevaughn Feb 12 '12 at 23:28
  • @ruevaughn, the idea was to populate position select with default value, as you requested. For example if Category has 0 subcategories, the `subcategories_with_placeholder` will return array with one `Subcategory` with position 1. In other cases it will return array with all subcategories of `Category` plus one `Subcategory` that acts like placeholder for new one. – Mark Huk Feb 13 '12 at 09:26
  • Thanks your explanation cleared it up. I realize I was adding two items into array like you said instead of applying the position field to the current category. My new line looks like this and works `result = [Subcategory.new(:position => (subcategories.length + 1))]` – ruevaughn Feb 13 '12 at 21:06