dropdown list in ruby on rails - ruby-on-rails

I want to display values to drop down list from Database.
For that in my controller class i did the following to get the values from db and its getting properly.
#value = Message.find(:all)
<Message ID: 14448, SlNo: 609">, #<Message ID: 14448, SlNo: 610">
How can i display the SlNo values to drop down list.Here is the code am using and getting error!I don't know how to set values inside a collection_select.Please help me!!
<% #value.each do |d| %>
<%=collection_select(:value, :id, #value, :id, { selected: params.fetch(:value, {})[:id].to_i, :prompt => "-Select a device" }) %>
<% end %>
Table names getting
["UniqueDeviceID", "SlNo"]
Model
class MessageDetail < ActiveRecord::Base
# attr_accessible :title, :body
set_table_name 'DeviceDetails'
set_primary_key 'SlNo'
end

instead of
<% #value.each do |d| %>
<%=collection_select(:value, :id, #value, :id, { selected: params.fetch(:device, {})[:id].to_i, :prompt => "-Select a device" }) %>
<% end %>
use
<%= collection_select :value, :id, #value, :id, :S1No, { selected: params.fetch(:device, {})[:id].to_i, :prompt => "-Select a device" } %>
UPDATE: explanations for passed parameters
:value = a symbol representation of the record you want to update, it may also not be an instance record but just a symbol that will be used in the naming convention of the select tag
:id = the column that you wish to update
#value = the collection to show the choices
:id = the method you want to use that will be passed as the value of the selected value
:S1No = the method that will be used as the label for the options of the select tag

# START
f.collection_select :id, Message.all(:order => "name"), :id, :name, :include_blank => true
# END
OR
# START
messages_arr = []
messages = Message.all(:order => "name")
messages.each do |msg|
messages_arr << [msg.name, msg.id]
end
f.select(:id, options_for_select(messages_arr), {:include_blank => 'Include All'}, {:class=>"span12"})
# END

Related

Use activeadmin-ajax_filter gem in nested forms

I'm using ActiveAdmin for an admin panel. In the nested form, I need to use some filtering, for example, in the dropdown I need to select an option name, and in the second dropdown should be displayed the option's values.
For this, I want to use activeadmin-ajax_filter gem. Option and OptionValue are connected with each other: Option has_many :option_values, and OptionValue belongs_to Option. I create option_values through the nested form when I create the Option.
Then, I have a Product model, in which via nested form I create a Variant. So, Variant belongs_to :option_value belongs_to :product and OptionValue has_many :variants, Product has_many :variants.
Just for now, when I want to create a new variant, I can select all the option values I have in the db. I want to select an option (for example a size), and then, in a dropdown below - select the appropriate values (XL, S, and so on).
The code for my active_admin resources is:
ActiveAdmin.register Product do
permit_params :category_id, :name, :description, :short_description, :image, :subtitle,
product_currencies_attributes: [:id, :product_id, :currency_id, :price, :_destroy],
variants_attributes: [:id, :product_id, :in_stock_id, :sold_out_id, :option_value_id, :image, :visible,
:orderable, :_destroy]
index do
column :id
column :image do |product|
image_tag(product.image.url(:thumb)) if product.image
end
column :category_id do |product|
category = Category.find(product.category_id)
link_to category.name, admin_category_path(category)
end
column :name
column :short_description
column :description do |product|
product.description.truncate(90)
end
column :subtitle
column :created_at
column :updated_at
actions
end
show do
tabs do
tab 'Product' do
attributes_table do
row :id
row :image do
image_tag(product.image.url(:medium))
end
row :category_id do
category = Category.find(product.category_id)
link_to category.name, admin_category_path(category)
end
row :name
row :short_description
row :description
row :subtitle
row :created_at
row :updated_at
end
end
tab 'Prices' do
attributes_table do
row :prices do
div do
product.product_currencies.each do |product_currency|
div do
"#{Currency.find(product_currency.currency_id).name}: #{product_currency.price}"
end
end
end
end
end
end
tab 'Variants' do
div do
'Variants will be here soon =)'
end
end
end
end
form do |f|
tabs do
tab 'Product' do
f.inputs do
f.input :category_id, as: :select, collection: Category.all.collect { |category| [category.name, category.id] }
f.input :name
f.input :short_description
f.input :description
f.input :subtitle
f.input :image, as: :file
end
end
tab 'Price' do
f.inputs do
f.has_many :product_currencies, allow_destroy: true, heading: false, new_record: 'Add New Price' do |product_currency|
product_currency.template.render partial: 'product-price-form', locals: { product_currency: product_currency,
product_id: params[:id].to_i }
end
end
end
tab 'Variants' do
f.inputs do
f.has_many :variants, allow_destroy: true, heading: false, new_record: 'Add new Variant' do |variant|
variant.template.render partial: 'variant-form', locals: { variant: variant, product_id: params[:id].to_i }
end
end
end
tab 'SEO' do
div do
'SEO inputs will be here'
end
end
end
f.actions
end
end
So, I've installed activeadmin-ajax_filter gem. I tried to follow the documentation, but as a result - nothing. As far, as I understand, I have to put this line of code to my Option activeadmin model: activeadmin-ajax_filter, and in the form use this:
f.input :option, as: :ajax_select, data: {
url: filter_admin_options_path,
search_fields: [:name],
static_ransack: { active_eq: true },
ajax_search_fields: [:option_value_id],
}
But still - nothing. By the way, the partial is:
<% if #product.new_record? %>
<% if Product.any? %>
<% new_product_id = Product.order(id: :desc).first.id + 1 %>
<% variant.input :product_id, as: :hidden, input_html: { value: new_product_id } %>
<% else %>
<% variant.input :product_id, as: :hidden, input_html: { value: 1 } %>
<% end %>
<% else %>
<% variant.input :product_id, as: :hidden, input_html: { value: product_id } %>
<% end %>
<% variant.input :in_stock_id, as: :select, collection: InStock.all.collect { |in_stock| [in_stock.name, in_stock.id] } %>
<% variant.input :sold_out_id, as: :select, collection: SoldOut.all.collect { |sold_out| [sold_out.name, sold_out.id] } %>
<%# variant.input :option, as: :ajax_select, collection: Option.all.collect { |option| [option.name, option.id] },
# data: {
# url: filter_admin_options_path,
# serarch_fields: [:name],
# static_ransack: { active_eq: true },
# ajax_search_fields: [:option_value_id]
# }
#%>
<% variant.input :option_value_id, as: :select, collection: OptionValue.all
.collect { |option_value| [option_value.value, option_value.id] } %>
<% variant.input :visible %>
<% variant.input :orderable %>
<% variant.input :image, as: :file %>

Rails undefined method `map' for nil:NilClass on collection_select - The reference called may be nil

After reading through the other SO answers, it's pretty clear that there are some common themes.
Mostly this type of error seems to happen when the object called is not defined yet, but in this case we have a has_many relationship that may not have a referenced entry when building the selection.
Class Tag
property :name, type: String
has_many :in, :tagged, type: :CONCEPTUAL_TAG, model_class: :Artefact
end
One option is to do something like this:
<div class="field">
<%= f.label :tagged_id %><br>
<% if !#tag.tagged.empty? %>
<%= f.collection_select(:tagged, Artefact.all.sort { |a,b| a.name <=> b.name }, :id, :name, options = {:prompt => "Please Select an Item", :selected => #tag.tagged.map(&:id)}, html_options = {:multiple => true, :class=>"search"}) %>
<% else %>
<%= f.collection_select(:tagged, Artefact.all.sort { |a,b| a.name <=> b.name }, :id, :name, options = {:prompt => "Please Select an Item"}, html_options = {:multiple => true, :class=>"search"}) %>
<% end %>
</div>
But this is definitely not DRY.
Is there a way to select nothing when there is no association, and pre-populate when there is while keeping to a single f.collection_select?
You don't have to use the condition in your view. Even if there are no items in #tag.tagged, it is still an ActiveRecord::Relation instance, so you can go ahead and just call map on it:
<%= f.collection_select(:tagged,
Artefact.all.sort { |a,b| a.name <=> b.name },
:id,
:name,
options = {
:prompt => "Please Select an Item",
:selected => #tag.tagged.map(&:id)
},
html_options = {
:multiple => true,
:class=>"search"
})
%>

Rails simple_form create form when column type is JSON

I have a model (FooBar) with three columns:
Foo -> String
Bar -> JSON
Baz -> String
I want to create a form for this model
Bar has default attributes of: {zing: {}, zaz: {}, laz: {}}
I would like to have the following inputs:
f.input :foo
f.input :zing
f.input :zaz
f.input :laz
f.input :baz
I tried to do this using fields_for and passing in each key and converting it to a symbol:
bar.each do |k,v|
f.input k.to_sym
end
but the error I'm getting is that FooBar has undefined method of :zaz
Any ideas would be appreciated, thanks.
You should be able to do it like this:
f.simple_fields_for :bar do |bar_f|
bar.each do |k,v|
bar_f.input k.to_sym
end
end
Don't forget to allow the parameters in the controller.
You can do something like this:
class User < ActiveRecord::Base
serialize :preferences, HashSerializer
store_accessor :preferences, :blog, :github, :twitter
end
And then you will have access to blog, github and twitter just as if they were normal properties in the model and your form is going to look something like this:
= simple_form_for(#user, html: { class: "form" }) do |f|
= f.input :blog
= f.input :github
= f.input :twitter
You have more info in this link! https://github.com/plataformatec/simple_form/wiki/Nested-inputs-for-key-value-hash-attributes
Hope it helps!
Set #temp variable
#temp = FooBar.new
#temp.data = {zing: "", zaz: "", laz: ""}
This code works for me
<%= simple_form_for #temp do |f| %>
<%= f.simple_fields_for :data do |data_f| %>
<% #temp.data.each do |k,v| %>
<%= data_f.input k.to_sym %>
<% end %>
<% end %>
<%= f.button :submit %>
<% end %>
Don't forget about permission params
params.require(:temp).permit(data: [:zing, :zaz, :laz])
If you don't want to define accessors, you could do something like:
= simple_form_for(#foo_bar) do |f|
= f.simple_fields_for :bar do |bf|
= bf.input :zing, input_html: { value: f.object.bar[:zing] }
= bf.input :zaz, input_html: { value: f.object.bar[:zaz] }
= bf.input :laz, input_html: { value: f.object.bar[:laz] }
You would need to initialise bar with {} in your controller

Refactoring of many if statements for params[...], inside controller action

I have such code, for making chain selects in my form
View for index action:
<%= form_tag do %>
<%= collection_select(*#brands_select_params) %>
<%= collection_select(*#car_models_select_params) %>
<%= collection_select(*#production_years_select_params) %>
<% # Пока еще никто ничего не выбрал %>
<%= submit_tag "Send", :id => "submit", :name => "submit" %>
And my controller:
class SearchController < ApplicationController
def index
#brands = Brand.all
#car_models = CarModel.all
if (params[:brand].blank?)
#brands_select_params = [:brand, :id, #brands, :id, :name, :prompt => "Выбирай брэнд"]
if params[:car_model].blank?
#car_models_select_params = [:car_model, :id, #car_models, :id, :name, { :prompt => "Model" }, \
{ :disabled => "disabled" }]
#production_years_select_params = [:production_year, :id, #car_models, :id, :name, { :prompt => "Year" }, \
{ :disabled => "disabled" }]
end
else
#brands_select_params = [:brand, :id, #brands, :id, :name, { :selected => params[:brand][:id] } ]
if params[:car_model].blank?
#car_models_select_params = [:car_model, :id, Brand.find(params[:brand][:id]).car_models, :id, :name, \
{ :prompt => "And model now" } ]
#production_years_select_params = [:production_year, :id, #car_models, :id, :name, { :prompt => "Year" }, \
{ :disabled => "disabled" } ]
else
#car_models_select_params = [:car_model, :id, Brand.find(params[:brand][:id]).car_models, :id, :name, \
{ :selected => params[:car_model][:id] } ] unless params[:car_model][:id].empty?
#production_years_select_params = [:production_year, :id, CarModel.find(params[:car_model][:id]).production_years, :id, :year, \
{ :prompt => "And year now" } ] unless params[:car_model][:id].empty?
end
end
end
end
As you can see, too many ifs in my controller code. And i gonna add more conditions there. After that anyone who read that code will get brain corruption. So i just wanna make it in real Ruby way, but don't know how. Please, help, guys. How should i refactor this bunch of crap?
I think a big part of the problem is you're doing too much in your controller. Generating markup (and IMO that includes building parameter lists for form helpers) should be done in views and view helpers. So:
module SearchHelper
def brand_select brands, options={}
collection_select :brand, :id, brands, :id, :name, :options
end
def car_model_select car_models, options={}
collection_select :car_model, :id, car_models, :id, :name, options
end
def production_year_select years, options={}
collection_select :production_year, :id, years, :id, :year, options
end
end
Then you can cut your controller down to this:
def index
#brands = Brand.all
#car_models = CarModel.all
#selected_brand_id = params[:brand] && params[:brand][:id]
#selected_car_model_id = params[:car_model] && params[:car_model][:id]
#production_years = #selected_car_model_id ?
[] : CarModel.find(#selected_car_model_id).production_years
end
And in your view:
<%= brand_select #brands, :prompt => "Выбирай брэнд",
:selected => #selected_brand_id
%>
<%= car_model_select #car_models, :prompt => "Model",
:selected => #selected_car_model_id
%>
<%= production_year_select #production_years, :prompt => "Year",
:selected => #selected_car_id
%>
I suspect you could simplify this even more using form_for and fields_for and get rid of the helpers entirely, but it depends a bit on how your model associations are set up.
There is no obvious solution to this kind of problem.
Generally, I try to keep the if / else architecture very clear and export all code into separate methods. 2 advantages here:
readability
easier unit testing
For your case, it would be:
class SearchController < ApplicationController
def index
#brands = Brand.all
#car_models = CarModel.all
if (params[:brand].blank?)
#brands_select_params = [:brand, :id, #brands, :id, :name, :prompt => "Выбирай брэнд"]
if params[:car_model].blank?
#car_models_select_params, #production_years_select_params = get_card_model(#car_models)
end
else
#brands_select_params = [:brand, :id, #brands, :id, :name, { :selected => params[:brand][:id] } ]
if params[:car_model].blank?
#car_models_select_params, #production_years_select_params = foo_method(#car_models)
else
#car_models_select_params, #production_years_select_params = bar_method
end
end
end
def get_card_model car_models
[
[:car_model, :id, car_models, :id, :name, { :prompt => "Model" }, { :disabled => "disabled" }],
[:production_year, :id, car_models, :id, :name, { :prompt => "Year" }, { :disabled => "disabled" }]
]
end
end

Make select list output in alphabetical order in Rails?

I have a select list in my model which lists a persons name with their employers name:
<li>Case Handler Name<span><%= f.select :person_id, Person.all.collect { |x| [x.name_and_company, x.id] } %></span></li>
def name_and_company
return "#{personname} (#{company})"
end
Is it possible to force the select list to output in alphabetical order?
I am assuming I would put an order tag in there...somewhere?
(:order => 'personname DESC')
Thanks,
Danny
You can do it like this
# controller
#people = Person.order_by('personname ASC').collect {|x| [x.name_and_company, x.id] }
# model
named_scope :order_by, lambda { |o| {:order => o} }
# view
<%= f.select :person_id, #people %>
Answer:
#users_controller.rb
def index
#people = Person.alphabetically
end
#user.rb
scope :alphabetically, order("name ASC")
#index.haml
= f.select :person_id, #people.all.collect { |p| [p.name, p.id] } %>
Even easier ...
<%= f.select :name, options_from_collection_for_select(Person.order("name ASC"), :name, :name), :prompt => 'Select' %>
Note: Doesn't require custom methods or additions to controller

Resources