I have a has_many, through: relationship in my Rails application.
Groups Model
class Group < ApplicationRecord
has_many :usergroups
has_many :users, through: :usergroups
end
User Model
class User < ApplicationRecord
has_many :groups, through: :usergroups
end
Usergroups Model
class Usergroup < ApplicationRecord
belongs_to :user
belongs_to :group
end
In my route http://localhost:3000/usergroups/new I have this form.
<%= form_with(model: usergroup, local: true) do |form| %>
<div class="field">
<%= form.label :user_id %>
<%= form.text_field :user_id, id: 'user', data: { autocomplete_source: User.order(:email).map(&:email) } %>
</div>
<div class="field">
<%= form.label :group_id %>
<%= form.text_field :group_id, id: 'group', data: { autocomplete_source: Group.order(:group_name).map(&:group_name) } %>
</div>
<%= form.submit %>
<% end %>
I am using jQuery autocomplete to search for these fields with the data attribute being whatever the user is entering into the User and Group field.
Since I need the user_id and the group_id to be able to add these users I am running into an issue because it is populating the user_email and group_name instead of the user_id and group_id. How can I add these users with the email and group name or add a hidden field with the id based on the group_name and user_email they add?
You can set the value of the selected option using select event listener for each combo box, but before that, you need to get the id of group and email:
Form:
// Update the 'data' attribute for both text fields, so you will get the id and value:
<%= form_with(model: usergroup, local: true) do |form| %>
<div class="field">
<%= form.label :user_id %>
<%= f.hidden_field :user_id %>
<%= form.text_field :user_id, id: 'user', data: { autocomplete_source: User.order(:email).map{ |item| {id: item.id , value: item.email} } } %>
</div>
<div class="field">
<%= form.label :group_id %>
<%= f.hidden_field :group_id %>
<%= form.text_field :group_id, id: 'group', data: { autocomplete_source: Group.order(:group_name).map{ |item| {id: item.id , value: item.group_name } } } %>
</div>
<%= form.submit %>
<% end %>
Javascript:
//below events can be combined into one
$("#user").autocomplete({
// suppose ui represents the returned value
select: function( event, ui ) {
$("#user").attr('data-selected-id', ui.item.id);
// to set a hidden field
$('[name="usergroup[user_id]"]').val(ui.item.id);
console.log(ui.item);
return false;
}
});
$("#group").autocomplete({
// ui.item represents the returned object { id: # , value: ''}
select: function( event, ui ) {
this.value = ui.item.value;
$("#group").attr('data-selected-id', ui.item.id);
// to set a hidden field
$('[name="usergroup[group_id]"]').val(ui.item.id);
console.log(ui.item);
return false;
}
});
Related
I am trying to create a form that updates 2 tables - commission_type and commission_tier.
I created the models, controller and form but when I submit it, my commission_tier table does not update. Only my commission_type table updates.
Can someone take a look at my code and tell me what I am doing wrong? I have combed through my code trying to find the mistake, and I cannot find it.
My models
class CommissionType < ApplicationRecord
has_many :commission_tiers
accepts_nested_attributes_for :commission_tiers
end
class CommissionTier < ApplicationRecord
belongs_to :commission_types, optional: true
end
My controller
class Admin::CommissionTypesController < Admin::BaseController
def index
#commission_types = CommissionType.all
end
def new
#commission_type = CommissionType.new
#commission_type.commission_tiers.build
end
def create
#commission_type = CommissionType.new(commission_type_params)
if #commission_type.save
redirect_to admin_commission_types_index_path
else
render "new"
end
private
def commission_type_params
params.require(:commission_type).permit(:name, :active, :allow_mass_update, :plan,
commission_tiers_attributes: [:id, :increment_value, :rate, :commission_type_id])
end
end
My form
<%= simple_form_for #commission_type, url: admin_commission_types_index_path, wrapper: :bootstrap2, :html => { :class => 'form-horizontal' } do |f| %>
<fieldset>
<legend>Properties</legend>
<%= f.input :name, label: 'Commission Name' %>
<%= f.input :active, as: :boolean, label: 'Active?', label_html: { class: 'padding-top' } %>
<%= f.input :allow_mass_update, as: :boolean, label: 'Allow mass update?', label_html: { class: 'padding-top' } %>
<%= f.input :plan, input_html: {id: 'dropdown'},
label: 'Commission Type',
collection: [ ['Select One..', 'select'], ['Flat', 'flat'], ['Flat +', 'flat_plus' ], ['Promotional', 'promotional'], ['Straight', 'straight'], ['Waterfall', 'waterfall'], ['Sliding Scale', 'sliding_scale'] ],
selected: 'select'
%>
</fieldset>
<fieldset id="flat">
<legend>Flat Commission</legend>
<%= f.simple_fields_for :commission_tiers do |builder| %>
<%= builder.input :rate %>
<%= builder.input :increment_value %>
<% end %>
</fieldset>
My form is displaying and working
UPDATE
Some additional details
CommissionType column values = [:name, :active, :allow_mass_update, :plan]
CommissionTier column values = [:id, :increment_value, :rate, :commission_type_id]
Also, when I submit my form, here is an example of what my params are
<ActionController::Parameters {"name"=>"asdf", "active"=>"1", "allow_mass_update"=>"1", "plan"=>"flat", "commission_tiers_attributes"=><ActionController::Parameters {"0"=><ActionController::Parameters {"rate"=>"45"} permitted: true>} permitted: true>} permitted: true>
I am using Simple Form in a Rails application in which a FormsController controller was defined as follow :
class FormsController < ApplicationController
def index
#forms = Form.all
end
def new
#form = Form.new(form_params)
end
...
private
def form_params
params.require(:form).permit(:user, :name, :tag, :link, :repo)
end
end
A new view is used to get some inputs from user
<div class="form">
<%= simple_form_for #param do |f| %>
<div class="form-inputs";>
<%= f.input :user %>
<%= f.input :name %>
<%= f.input :tag %>
<%= f.input :link %>
<%= f.input :repo %>
</div>
<div class="form-actions">
<%= f.button :submit, "Create", class: "btn-primary" %>
</div>
<% end %>
</div>
I checked what's the generated name for a each field using inspect :
<input type="text" name="form[user]" id="form_user">
Printing parameters in controller while submitting a form returns :
{“user”=>”value1”, “name”=>”value2”, “tag”=>”value3”, “link”=>”value4”, “repo”=>”value5”}
From now, I would like to duplicate that's simple form few times. So, I first updated the field name from form[<parameter>] to form[1][<parameter>]
<div class="form-inputs";>
<%= f.input :user, input_html: { name: 'form[1][user]' } %>
<%= f.input :name, input_html: { name: 'form[1][name]' } %>
<%= f.input :tag, input_html: { name: 'form[1][tag]' } %>
<%= f.input :link, input_html: { name: 'form[1][link]' } %>
<%= f.input :repo, input_html: { name: 'form[1][repo]' } %>
</div>
What I get from now as parameters output is :
"form"=>{"1"=>{"“user”"=>"value1", "“name”"=>"value2", "“tag”"=>"value3", "“link”"=>"value4", "“repo”"=>"value5"}}
What's the best way to dynamically allocate the id to the form[<id>][user] to the field ?
Is it possible to get parameters formatted as follow ?
form => { 1 => {user: "user1" }, 2 => {user: "user2" }, 3 => {user: "user3" }.. }
form => { 1 => {name: "name1" }, 2 => {name: "name2" }, 3 => {name: "name3" }.. }
...
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 %>
I have a double nested form:
<%= simple_form_for #item, html: { class: "create-item-form" } do |item_builder| %>
<div class="well">
<%= item_builder.input :name, required: false, error: false, label: "item name" %>
<%= item_builder.input :description, as: :text, required: false, error: false, label: "How do users earn this item?" %>
<%= item_builder.input :tag_list, required: false, label: "Tags (these will help users find your item)" %>
<%= item_builder.simple_fields_for :user_items do |user_item_builder| %>
<%= user_item_builder.input :foo, as: :hidden, input_html: { value: "bar" } %>
<%= user_item_builder.simple_fields_for :user_item_images do |user_item_images_builder| %>
<%= user_item_images_builder.input :foo, as: :hidden, input_html: { value: "bar" } %>
<%= user_item_images_builder.input :picture, as: :file, required: false,
error: false, label: "Pictures of you earning this item",
input_html: { multiple: true,
name: "item[user_items_attributes][0][user_item_images_attributes][][picture]" } %>
<% end %>
<% end %>
</div>
<div class="clearfix">
<%= item_builder.submit 'Submit new item request', class: "btn btn-primary pull-right inherit-width" %>
</div>
<% end %>
When a user doesn't upload a file for the user_item_image I need to display an error message. I wrote a custom validation:
user_item_image.rb
class UserItemImage < ActiveRecord::Base
include PicturesHelper
attr_accessor :foo
mount_uploader :picture, PictureUploader
belongs_to :user_item
validate :picture_size
validate :has_picture
private
def has_picture
errors.add(:base, 'You must include at least one picture.') if picture.blank?
end
end
But I get the error message:
User items user item images base You must include at least one picture.
How can I rewrite the validation so that it doesn't show the attribute and only shows the message.
Why not use
validates :picture, presence: true
on your useritem model
I am trying to make a new Deliverable which has nested DeliverableDates. The Deliverable's attributes, such as title, save but the nested attributes in DeliverableDates don't. What am I missing?
Many Thanks
class ProgramManager::DeliverablesController < ProgramManager::ApplicationController
...
def new
#deliverable = #program.deliverables.build
#program.groups.each do |group|
#deliverable.deliverable_dates.build(group_id: group.id)
end
clean_deliverables
3.times { #deliverable.select_options.build }
end
def create
delete_empty_select_options
#deliverable = #program.deliverables.new(params[:deliverable])
clean_deliverables
if #deliverable.save
redirect_to program_deliverables_path(#program), success: 'Deliverable created successfully'
else
#program.groups.each do |group|
#deliverable.deliverable_dates.build(group_id: group.id)
end
render :new
end
end
...
end
-
<%= form_for [#program, deliverable], html: { class: 'form-horizontal' } do |f| %>
<%= render 'shared/error_messages', object: deliverable %>
...
<div class="in-out <%= "hidden" if deliverable.is_by_date? %>" id="in-out">
<%= f.fields_for :deliverable_dates do |d| %>
<h5><%= Group.find(d.object.group_id).name %></h5>
<div class="form-group">
<%= d.label :in_date, 'In Date', class: 'col-md-2 control-label' %>
<div class="col-md-10">
<%= d.text_field :in_date, class: 'form-control input-sm datepicker', id: 'deliverable_in_date_new', placeholder: 'In Date' %>
</div>
</div>
<div class="form-group">
<%= d.label :out_date, 'Out Date', class: 'col-md-2 control-label' %>
<div class="col-md-10">
<%= d.text_field :out_date, class: 'form-control input-sm datepicker', id: 'deliverable_out_date_new', placeholder: 'Out Date' %>
</div>
</div>
<% end %>
</div>
...
<div class="form-group">
<div class="col-md-10 col-md-offset-2">
<%= f.submit 'Save changes', class: 'btn btn-primary' %>
</div>
</div>
<% end %>
-
class Deliverable < ActiveRecord::Base
include Folderable
include Reportable
attr_accessible :program_id, :deliverable_type, :is_by_date, :title, :file_cabinet_folder, :select_options_attributes
attr_accessor :in_data_cell, :out_data_cell, :by_data_cell
belongs_to :program
has_many :deliverable_dates, dependent: :destroy
has_many :select_options, as: :optionable, dependent: :destroy
has_many :deliverable_data, dependent: :destroy
has_many :folders, as: :folderable, dependent: :destroy
delegate :in_date, :out_date, :by_date, to: :deliverable_dates
accepts_nested_attributes_for :select_options, allow_destroy: true
accepts_nested_attributes_for :deliverable_dates, allow_destroy: true
...
end
-
class DeliverableDate < ActiveRecord::Base
attr_accessible :group_id, :deliverable_id, :in_date, :out_date, :by_date
belongs_to :group
belongs_to :deliverable
validates :group_id, presence: true
validates :deliverable_id, presence: true
scope :past_due, -> { where('(out_date is not null and out_date < ?) or (by_date is not null and by_date < ?)', Date.today, Date.today) }
scope :upcoming, -> { where('((in_date is not null and in_date >= ?) and (out_date is not null and out_date >= ?)) or (by_date is not null and by_date >= ?)', Date.today, Date.today, Date.today) }
scope :current_deliverables, -> { where('((by_date > ? and by_date <= ?) or (in_date > ? and in_date <= ?) or (out_date > ? and in_date <= ?) or (in_date >= ? and out_date <= ?))', Date.today, 10.days.from_now, Date.today, 5.days.from_now, Date.today, 5.days.from_now, Date.today, Date.today) }
end
In order to make the 'accepts_nested_attributes_for' work properly ":deliverable_dates_attributes" must be added to the attr_accessible for the Deliverable