I have two collection_select field in my form. One is to select category and the other is to select subcategory. I want the subcategory field to populate as per the category gets selected. I someone select category 1 then the subcategories belong to category 1 will be populated in the second collection_select field. I'm not sure what to do. What modifications I need in the following code I tried.
<div class="field">
<%= f.label :category_id %><br>
<%= f.collection_select(:category_id, Category.find(:all), :id, :name) %>
</div>
<div class="field">
<%= f.label :subcategory_id %><br>
<%= f.collection_select(:subcategory_id, Subcategory.where(category_id: :category_id), :id, :name) %>
</div>
You need to ajax to get this functionality
Try this Example:
form.html.erb
<script>
$(document).ready(fnction(){
$('#category_id').change(function(){
var value = $(this).val()
$.ajax({
type: 'POST',
url: 'options',
data: {id: value},
success: function(data){
$('#subcategory').html(data)
}
})
})
})
</script>
<div class="field">
<%= f.label :category_id %><br>
<%= f.collection_select(:category_id, Category.find(:all), :id, :name) %>
</div>
<div id="subcategory"></div>
controller:
def options
id = params[:id]
#subcategory = Subcategory.where(:category_id => id)
render :partial => 'options'
end
_options.html.erb:
<%= f.label :subcategory_id %><br>
change this line
<%= f.collection_select(:subcategory_id, #subcategory, :id, :name) %>
to
<%= f.input :subcategory_id, #subcategory %>
and finally in Routes.rb
post '/options' => 'categories#options'
You have two ways:
Use jquery. Something like that -
$(select_category).on('change', function(){ update_subcategory_options() })
where update_subcategory_options() - ajax request or another code.
Or use collection select with group (http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/option_groups_from_collection_for_select)
Related
I'm new to rails to bear with me.
This concerns two of my models: Product and Manufacturer.
When creating a new product the user can select which manufacturer the product belongs to from a drop down list. The problem is that I can't get this manufacturer to save.
I know I have to add some code to the controller and I've tried various things but to no avail.
Here's the view:
<h1>New Product</h1>
<%= form_for(#product) do |f| %>
<div>
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :market_price, 'Market Price' %>
<%= f.text_field :market_price %>
</div>
<div>
<%= f.label :sell_price, 'Sell Price' %>
<%= f.text_field :market_price %>
</div>
<div>
<%= f.label :stock_level, 'Stock Level' %>
<%= f.text_field :stock_level %>
</div>
<div>
<%= f.label :manufacturer, 'Manufacturer' %>
<%= f.collection_select(:manufacturer, Manufacturer.all, :id, :name, prompt: true) %>
</div>
<div>
<%= f.label :location, 'Location' %>
<%= f.collection_select(:location, Product.all, :id, :location, prompt: true) %>
</div>
<br> </br>
<div>
<%= f.submit "Create Product" %>
</div>
And here's part of the controller:
def create
#product = Product.new(params[:product].permit(:name, :market_price, :sell_price, :stock_level, :location))
#product.save
flash[:notice] = 'Product Created'
redirect_to #product
end
end
After hours of trying several nesting methods, I still can't get this to work.
Surely it's very common to save fields from various models on one page???
You would usually nest your routes, so that products were within manufacturer:
resources :manufacturer do
resources :products
end
Then your form would be a form for an array:
form_for([#manufacturer, #product]) do |f|
f.hidden_field :manufacturer_id, value: #manufacturer.id
This allows you to pass in the ID of both the manufacturer and the product.
Now in your controller you can use something like the following, provided the associations are set up, such as product belongs_to :manufacturer and manufacturer has_many :products
#manufacturer = find(params[:manufacturer_id])
#product = #manufacturer.products.create()
In your form, you need to have a field for manufacturer_id, not manufacturer. You would change f.collection_select(:manufacturer to be f.collection_select(:manufacturer_id.
Then, in your controller, you need to add manufacturer_id to the list of parameters you are permitting in your permit method call. So it would be Product.new(params[:product].permit(:name, :market_price, :sell_price, :stock_level, :location, :manufacturer_id)).
I am trying to make use of the enum feature that has been added to Rails. I had been waiting for this for quite some time.
Here is how I set it up:
Product model:
enum category: [:t_shirt, :hoodie, :jacket]
Product controller:
def create
#product = Product.new(product_params)
if #product.save
redirect_to #product, notice: 'Product was successfully created.' }
else
render :new
end
end
def product_params
params.require(:product).permit(:title, :description, :category, :price)
end
New form
<%= form_for(#product) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :category %><br>
<%= f.select :category, Product.categories, include_blank: "Select a category" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This correctly populates the drop-down field in my form with the values of the different enum options which I have defined in the model.
However, when I submit the form having selected one of the categories from the drop-down, it gives me an error:
'0' is not a valid category
Even though my category field is an integer field and '0' is the correct integer associated with the category I selected in my form.
It also highlights the following line from the create method in my Product controller as the place where the error occured:
#product = Product.new(product_params)
I am completely confused as to why this is happening. Would really appreciate some help.
Thank you.
Instead:
<%= f.select :category, Product.categories, include_blank: "Select a category" %>
Try:
<%= f.select :category, Product.categories.keys, include_blank: "Select a category" %>
Explain:
In Product.categories hash {"t_shirt"=>0, "hoodie"=>1, "jacket"=>2} but in Product.categories.keys array what you need ["t_shirt", "hoodie", "jacket"] for select helper.
I'm fairly new to rails and I'm building my first app. I've searched the web for a correct answer but couldn't find any that worked for my case.
I'm using simple form, with rails 4 and bootstrap 3. I have a :location dropdown on a (#employees) model and I want to populate it with a job_title column from my #positions model. I've used a scaffold to generate my position MVC + job_title:string job_description:string.
How can I populate my :location dropdown (on my employees form) with values from :job_title (from #positions model)? I currently have my code as:
<div class="col-md-6 pad-10">
<% options = options_from_collection_for_select(#positions, 'id', 'job_title') %>
<%= f.select :location, options, :input_html => { class: "form-control" } %>
</div>
But as you know, that doesn't work. Any help is appreciated!
Solution:
<div class="col-md-6 pad-10">
<% options = options_from_collection_for_select(Position.all, 'id', 'job_title') %>
<%= f.select :location, options, :input_html => { class: "form-control" } %>
</div>
I used Position.all instead of #positions.
options_from_collection_for_select needs an Array. Docs
So try using Modelname.all instead of #positions or re-declare #positions with #positions = Modelname.all
Because you are using simple_form, you can render a select box for a collection like this:
<%= f.input :location, collection: #positions, label_method: :job_title, value_method: :id, input_html: { class: "form-control" } %>
This should do it for you if you want the id ofan Position object be written to the location field. If you want the job_title cahnge :id to :job_title.
<div class="col-md-6 pad-10">
<%= f.label :location %><br />
<%= f.collection_select :location, #positions, :id, :job_title %>
</div>
I used Position.all instead of #positions.
<div class="col-md-6 pad-10">
<% options = options_from_collection_for_select(Position.all, 'id', 'job_title') %>
<%= f.select :location, options, :input_html => { class: "form-control" } %>
</div>
okay, if you have a habtm relationship between category and articles, now through the category index page is it possible to perform a filter, using two select box populated with the categories, which shows articles belonging to either or both category?
this is how i tried.
category controller
def index
#categories = Category.all
end
def show
#category = Category.find(params[:name][:id])
end
category index page
<%= form_for :categories, :url => {:action => :show}, :method => "get" do |f| %>
<div class="field">
<%= f.label :category %><br />
<%= collection_select(:name, :id, Category.all, :id, :name) %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= collection_select(:name, :id, Category.all, :id, :name) %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
category show page
<ul>
<% #category.articles.each do |a| %>
<li><%= a.author %></li>
<li><%= a.title%></li>
<li><%= a.pub_date%></li>
<% end %>
</ul>
at this stage it only presents articles, based on the second collection_select.
also, is habtm altogether necessary to do something like this? can this be done if there is a column instead in the articles model? which is the best way?
thanks
I'd suggest to rename the second collection_select ids and try a Where clause with OR in your controller. Something like that:
def index
#categories = Category.all
end
def show
#category = Category.where(:id => [params[:name][:id1], params[:name][:id2]])
end
and in your index page:
<%= form_for :categories, :url => {:action => :show}, :method => "get" do |f| %>
<div class="field">
<%= f.label :category %><br />
<%= collection_select(:name, :id, Category.all, :id1, :name) %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= collection_select(:name, :id, Category.all, :id2, :name) %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
I did not test it, but this is the idea.
Hope it helps
I have a form for users to upload pictures with some other informations like name and description. I have two databases tables: one is albums and the other is photos. In photos table there is a field called album_id which connects the photo to the album.
<%= form_for(#photo, :html => { :multipart => true }) do |f| %>
<div>
<div class='form_text'> Add Photo </div>
<%= f.file_field :image %>
</div>
<div>
<div class='form_text'> Name </div>
<%= f.text_field :name %>
</div>
<div>
<div class='form_text'> Description </div>
<%= f.text_field :description %>
</div>
<div>
<%= collection_select(:album, :album_id, Album.all, :id, :name, :prompt => true) %>
</div>
<div>
<%= f.submit 'Upload' %>
</div>
So my problem is that how I can pass the selected value of album_id as same as other values. Maybe I am not clear enough, I think the selection is not added into the f object, so when the value passes when click on Upload, name, description and the photo are passed in as one object and the album_id is passed as another object. How can make the selection into the f object?
I think it should be
<%= collection_select(:photo, :album_id, Album.all, :id, :name, :prompt => true) %>
So it would generate a select with the id photo[album_id], as your other fields (doc).