Multiple select in administrate - ruby-on-rails

Since administrate does not yet have support for multiple selects. Has anyone created a custom multiple select? Preferably one that works like the HasMany select.

Here it is in case someone else needs it:
app/fields/multiple_select_field.rb
# app/fields/multiple_select_field.rb
require "administrate/field/base"
class MultipleSelectField < Administrate::Field::Select
def to_s
data
end
def self.permitted_attribute(attribute)
{ attribute.to_sym => [] }
end
def permitted_attribute
self.class.permitted_attribute(attribute)
end
end
app/views/fields/multiple_select_field/_form.html.erb
# app/views/fields/multiple_select_field/_form.html.erb
<div class="field-unit__label">
<%= f.label field.attribute %>
</div>
<div class="field-unit__field">
<%= f.select(
field.attribute,
options_from_collection_for_select(
field.selectable_options,
:to_s,
:to_s,
field.data.presence,
),
{}, multiple: true,
) %>
</div>
app/views/fields/multiple_select_field/_index.html.erb
# app/views/fields/multiple_select_field/_index.html.erb
<%= field.to_param.join(', ') %>
app/views/fields/multiple_select_field/_show.html.erb
# app/views/fields/multiple_select_field/_show.html.erb
<%= field.to_param.join(', ') %>

Related

I'd like to add radio buttons to the Rails search function to allow narrowing the search

What I want to come true
I want to implement a search function using radio buttons. I want to be able to narrow down the search using radio buttons and search words.
I've gotten as far as how to implement search, but I can't figure out how to narrow it down with radio buttons. I would like to know how to do this.
code
View
<div class="form">
<%= form_with url: search_path, method: 'get' do |form| %>
<div class="search">
<%= form.text_field :search %>
<%= form.submit "Search" %>
</div>
#I don't know how to send the value of a radio button.
<div class="radio">
<%= form.label :search_check_box,"all", {value: :all} %>
<%= form.radio_button :search_check_box, :all %>
<%= form.label :search_check_box,"public", {value: : public} %>
<%= form.radio_button :search_check_box, :public %>
<%= form.label :search_check_box,"not_ public", {value: :not_ public} %>
<%= form.radio_button :search_check_box, :not_publick %>
</div>
<% end %>
</div>
controller
def search
#movies = Movie.search(params[:search])
end
model
class Movie < ApplicationRecord
def self.search(search)
if search
Movie.where('name LIKE ?', "%#{search}%")
else
Movie.all
end
end
end
You're falling to the classic trap of using a single class (Movie) to do way too much. Create a separate model to use to wrap the logic for searching:
class MovieQuery
include ActiveModel::Model
include ActiveModel::Attributes
VISIBILITY_OPTIONS = ["all", "public", "private"]
attribute :name
attritute :visiblity
def to_scope(base: Movie.all)
base.tap do |b|
b = base.where('name LIKE ?', "%#{ name }%") if name.present?
b = base.where(visiblity: visiblity) if ["public", "private"].include?(visiblity)
end
end
end
This model is not saved to the database - it simply serves to bind the user input to an object and apply the search filters. Its also the local place to add stuff like validations.
Then bind the form to your model:
<%= form_with model: #movie_query || MovieQuery.new, url: search_path, method: 'get' do |form| %>
<div class="search">
<%= form.label :name, 'Search by name' %>
<%= form.text_field :name %>
</div>
<div class="radio">
<%= form.label :visiblity %>
<%= form.collection_radio_buttons :visiblity,
MovieQuery::VISIBILITY_OPTIONS,
:itself,
:humanize
%>
</div>
<div class="actions">
<%= form.submit 'Search' %>
</div>
<% end %>
collection_radio_buttons is really meant to be used with objects (models) and the third and forth arguments are the text and label methods called on each object in the collection. By using itself and humanize you can use it with a simple array.
Then setup your controller to bind the inputs back to the model:
class MoviesController
def search
#movie_query = MovieQuery.new(search_parameters)
#movies = #movie_query.to_scope
end
private
def search_parameters
params.fetch(:movie_query) # its an optional parameter
.permit(:name, :visibility)
end
end

Using enum with select in a form_tag

user.rb
enum gender_type: [:male, :female]
scope :gender, -> (gender_type) { where gender_type: gender_type}
userscontroller
#users = User.gender(params[:gender_type]).paginate(page: params[:page]) if params[:gender_type].present?
index.html.erb
<%= form_tag users_path, method: :get do %>
<%= select_tag ?????? %>
<%= submit_tag "Search", :name => "nil", :id => "submit-gender" %>
<% end %>
the goal is to end up with:
example.com/users?gender_type=0 or example.com/users?gender_type=1
To get the mappings from a enum attribute you can use the pluralised version of the the enum attribute name:
User. gender_types
=> { male: 0, female: 1 }
You can call Hash.to_a to get an array of pairs that you can pass to options_for_select. But you may want to use .map to transform the keys.
class User
self.gender_options
# or use the I18n module to humanize the keys
self.gender_types.map { |k,v| [k.capitalize, v] }
end
end
<%= select_tag 'gender', options_for_select(User.gender_options) %>
Try that kind
select_tag 'gender', "<option value=0>male</option><option value=1>female</option>".html_safe
or smth like that
select_tag 'gender', options_for_select([["male",0],["female",1]])
and you can read rails api to find the solution
http://apidock.com/rails/ActionView/Helpers/FormTagHelper/select_tag
(I assume you mistyped in filename users.rb and it is a regular user.rb model)
User.gender_types will return a hash {"male" => 0, "female" => 1}. Sounds easy!
select_tag :gender_type, options_for_select(User.gender_types)
You can simply use like this
<%= form_for(user) do |form| %>
<%= form.select :gender_types, User.gender_types.keys.to_a %>
<% end %>
But assuming you use Rails Internationalization I18n (which I recommend) You may want to translate this enum like this in your view helper (or :
# app/helpers/users_helper.rb
def genders_select
User.gender_types.map do |k,v|
[User.human_enum_name(:gender_types, k), v]
end
end
and
<%= form_for(user) do |form| %>
<%= form.select :gender_types, #genders_select %>
<% end %>

Setting default value for Rails select helper block

How can I set default value in Rails select helper block?
<div class="field">
<label>Gender</label>
<%= f.select :gender, [], { prompt: 'Select gender', selected: 'Female' }, { :class => 'ui selection dropdown' } do %>
<% Subject.genders.keys.each do |c| %>
<%= content_tag(:option, value: c, class: 'item') do %>
<%= content_tag(:i, '', class: "#{c.downcase} icon") %>
<%= content_tag(:span, c) %>
<% end %>
<% end %>
<% end %>
</div>
I tried setting it with :selected option but it doesn't work.
I don't think if selected exist for f.select.
You can use options_for_select(values, value_selected)
Suggestion:
You can create a file named app/helpers/select_helper.rb. In this file, you create a function like this:
def subject_genders_values
Subject.genders.each do |c|
[c.value, c.value]
end
end
your function subject_genders_values can be re-used. And every time if you want a select box, you can create your function in this file.
Notice: add
include SelectHelper
in application_helper.rb
And your views:
<%= f.select :gender,options_for_select(subject_genders_values, 'Female') %>
The option Female will be selected if it's a part of the list.

How do I select a car make and then select model according to make?

In my rails project I have two models, Car Make & Car Model, with a 1:M relationship (i.e. one Audi has many Audi models).
In my Views page, I want a form with two input fields for car make & car model. Ideally, I will be able to input a car make (i.e. Audi) and the second input field will have a drop down menu with all the models available for the make (2016 Audi A6, 2017 Audi A7).
I've set up all the relations and in the models I have saved a foreign key of the make.
currently in _form.html.erb I have
<div class="field">
<%= f.label :make_id, "Make:"%><br>
<%#= f.number_field :make_id %>
<%= f.collection_select :make_id, Make.all,
:id,:makes_info, {:include_blank => 'Please Select'} %>
</div>
<div class="field">
<%= f.label :model_id, "Model:" %><br>
<%= f.collection_select :model_id, Model.all,
:id,:model_info, {:include_blank => 'Please Select'} %>
</div>
If you want it to truly be dynamic, you would need to use an AJAX request to update the second select after the first is picked. You'd also need to use the options_for_select method inside of the select tag
Some more info to accompany what was already provided.
It's known as dynamic select boxes:
#config/routes.rb
resources :makes do
get :models, on: :collection #-> url.com/makes/models
end
#app/controllers/makes_controller.rb
class MakesController < ApplicationController
def models
#make = Make.find(params[:make][:make_id])
respond_to do |format|
format.js
end
end
end
#app/views/makes/models.js.erb
$select = $("select#models");
$select.empty();
<% #make.models.each do |model| %>
$select.append($('<option>').text(<%=j model.name %>).attr('value', <%= model.id %>));
<% end %>
#views
<%= f.collection_select :make_id, Make.all, :id, :makes_info, {include_blank: 'Please Select'}, { data: { remote: true, url: make_models_path }} %>
<%= f.collection_select :model_id, Model.all, :id,:model_info, {include_blank: 'Please Select'}, { id: "models" } %>

Ruby On Rails - validate nested params in controller (must not be nil)

These are my params:
{"utf8"=>"✓", "authenticity_token"=>"0RYiIDDgmOk0gCDRkAgHvv+UIgp/BuU33CLThJXqOTE=",
"order"=>
{"operation_in_orders_attributes"=>
{"0"=>{"service_operation_id"=>"5"},
"1"=>{"service_operation_id"=>""},
"2"=>{"service_operation_id"=>"4"},
"3"=>{"service_operation_id"=>""},
"4"=>{"service_operation_id"=>""}},
"kontakt"=>"comment", "Car_id"=>"50"},
"commit"=>"Dodaj",
"car_id"=>"dw815gn"}
Order has many operation_in_orders
Order has many service_operations through OperationInOrder
OperationInOrder belongs to Order
OperationInOrder belongs to ServiceOperation
ServiceOperation has many operation_in_orders
ServiceOperation has many orders through OperationInOrder
My form:
<%= form_for #order, url: new_car_order_path(#car, #order), html: {class: "add_order"} do |r| %>
<%= r.label "Service", class: :add_order_label %>
<% 5.times do %>
<%= r.fields_for :operation_in_orders do |v| %>
<%= v.collection_select(:service_operation_id, ServiceOperation.all, :id, :nazwa,include_blank: true) %>
<!-- <%= v.text_field :order_id, value: #order.id, :style => "display:none" %> -->
<% end %>
<% end %>
<%= r.label "Kontakt", class: :add_order_label %>
<%= r.text_field :kontakt %>
<%= r.text_field :Car_id, value: #car.id, :style => "display:none" %>
<%= r.label " " %>
<%= r.submit "Add", class: "sub" %>
<%= link_to "Send",ordered_path(car_id: #car.id) , class: 'sub'%>
<% end %>
I have a form where I can choose five ServiceOperations at most to an order and save.
When I save, 5 new OperationInService objects/rows are made.
Is there a possibility to not create those join tables if corresponding field on form is blank?
For example:
I fill only 2 from 5 fields. I save only these two, not 5. Now I save nil values...
I have tried to validate in OperationInService model, but there was an error (rails do not recognize format in controller).
Any ideas?
Update the accepts_nested_form_for method call in Order model as below:
class Order < ActiveRecord::Base
has_many :operation_in_orders
accepts_nested_attributes_for :operation_in_orders, reject_if: proc { |attributes| attributes['service_operation_id'].blank? }
## ..
end
This way record for operation_in_orders would not be created if service_operation_id is blank.

Resources