in Main form
<%= p.fields_for :prd_allisland_flat_deliveries do |i| %>
<%= render(:partial => 'prd_allisland_flat_delivery_field', :locals => {:f => i})%>
<% end %>
in the prd_allisland_flat_delivery_field form partial
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_period %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_period, {placeholder: '0', class: 'form-control input_border input_field_text_align_right'})%>
</div>
<div class="col-md-2"></div>
</div>
<div class="row" style="padding-bottom: 25px">
<div class="col-md-2"></div>
<div class="col-md-4">
<%= f.label :delivery_rate %>
</div>
<div class="col-md-4">
<%= f.text_field(:delivery_rate, {placeholder: 'Rs. 0.00', class: 'form-control input_border input_field_text_align_right'})%>
</div>
</div>
in prd_item controller
**def new
#item = PrdItem.new
#item.build_prd_allisland_flat_delivery
end**
after writing this the create method
**
if #item.save
if #item.delivery_type == 1
#all_island_flat = PrdAllislandFlatDelivery.new(item_params[:prd_allisland_flat_deliveries_attributes])
#all_island_flat.save
end
end**
the item_params
def item_params
params.require(:prd_item).permit(:item_name, :brand, :item_no, :short_description, :long_description, :prd_type_id, :usr_vendor_property_id, :price,:base_price, :price_discount, :percentage_discount, :stock_count, :availability, :tags, :remove_image, :delivery_type , :min_stock_count,
prd_item_images_attributes: [:id, :image, :description, :link, :_destroy ],
prd_temp_variation_stores_attributes: [:id, :product_variations, :variation_items, :_destroy],
prd_temp_compound_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_temp_spec_stores_attributes:[:id,:compound, :compound_item, :_destroy],
prd_allisland_flat_deliveries_attributes: [:id,:delivery_period,:delivery_rate],
prd_province_vise_deliveries_attributes: [:id , :province_name , :delivery_rate, :delivery_period]
)
end
the rails consoler gets the attributes for the prd_allisland_flat_deliveries but the prd_all_island_flat_deliveries fill with null values
Is that your full create method? If so you need to understand that every request is separate from others, the create request doesn't know what happened in the new request.
In your create method you need to build your basic object, then update the object from the params.
def create
#item = PrdItem.new
#item.update(item_params)
if #item.save ...
Related
I have the following form:
<div class='panel' id='panel-advanced-search'>
<%= form_tag contacts_path, method: :get do %>
<div>
<div class='advanced_search'>
<div>
<%= label_tag "Contact Type" %>
<%= select_tag(:contact_type, options_for_select(Contact::TYPES, selected: params[:contact_type]), prompt: 'Any', class: 'customSelect') %>
</div>
<div>
<%= label_tag "Prospect Strength" %>
<%= select_tag(:prospect_strength, options_for_select(Contact::PROSPECT_STRENGTHS, selected: params[:prospect_strength]), prompt: 'Any', class: 'customSelect') %>
</div>
<div>
<%= label_tag "Customer" %>
<%= collection_select(:customer_account_id, :customer_account_id, Customer.order(:name), :id, :name, { prompt: '' }, class: 'customSelect select2') %>
</div>
<div>
<%= label_tag "Supplier" %>
<%= collection_select(:supplier_account_id, :supplier_account_id, Supplier.order(:name), :id, :name, { prompt: '' }, class: 'customSelect select2') %>
</div>
<div>
<%= label_tag "Company Name" %>
<%= text_field_tag :company_name %>
</div>
<div>
<%= label_tag "Name" %>
<%= text_field_tag :name %>
</div>
<div>
<%= label_tag "Job Title" %>
<%= text_field_tag :title %>
</div>
<div>
<%= label_tag "Postcode" %>
<%= text_field_tag :postcode %>
</div>
<div>
<%= label_tag :created_at, 'Created From' %>
<div class="date-picker">
<%= text_field_tag :created_at, nil, class: 'date-picker-select' %>
<span class="date-picker-btn">
<span class="icon-calendar" aria-hidden="true"></span>
</span>
</div>
</div>
<div>
<%= label_tag :updated_at, 'Created To' %>
<div class="date-picker">
<%= text_field_tag :updated_at, nil, class: 'date-picker-select' %>
<span class="date-picker-btn">
<span class="icon-calendar" aria-hidden="true"></span>
</span>
</div>
</div>
<div>
<%= label_tag "Tags" %>
<%= collection_select(:tag_list, :tag_list, #tags.order(:name), :name, :name, {}, { class: 'select2', multiple: true }) %>
</div>
<div>
<%= label_tag "Assignee" %>
<%= collection_select(:assigned_to, :assigned_to, User.all, :id, :name, { prompt: 'Any' }, class: 'customSelect select2') %>
</div>
<div>
<%= label_tag "Obsolete?" %>
<%= select_tag(:obsolete, options_for_select(['Obsolete', 'All'], selected: params[:obsolete]), prompt: 'Not obsolete?', class: 'customSelect') %>
</div>
<div>
<%= label_tag "Send Results To" %>
<%= select_tag(:subsequent_action, options_for_select([
['Report', 'report'],
['CSV Export', 'csv_export'],
['New Event', 'new_event']
]), prompt: 'None', class: 'customSelect') %>
</div>
</div>
<div class="advanced_search_btns">
<%= submit_tag submit_text %>
<%= link_to secondary_btn, contacts_path, class: 'btn-medium' %>
</div>
</div>
<% end %>
</div>
and the following method in the model
def self.advanced_search
Contact.where('
contact_type LIKE :search OR
prospect_strength LIKE :search OR
customer_account_id LIKE :search OR
supplier_account_id LIKE :search OR
company_name LIKE :search OR
name LIKE :search OR
title LIKE :search OR
postcode LIKE :search OR
created_at LIKE :search OR
updated_at LIKE :search OR
tag_list LIKE :search OR
assigned_to LIKE :search OR
obsolete LIKE :search
', search: "%#{search}%"
)
end
How do I go about using this method so the user can use this search form with multiple params? I already have the following in the index method for a basic search so I need to have both search forms
def index
#per_page = params[:per_page] || 20
#tags = ActsAsTaggableOn::Tag.all
if params[:search].present?
#contacts = Contact.search(params[:qs], params[:search]).order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: #per_page)
else
#contacts = Contact.all.order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: #per_page)
end
end
Edit Updated the form above to the complete form, ideally, I would like the forms functionality to be entirely in the model.
Edit #2
This is the basic search:
model
QUICK_SEARCH_FIELDS = {
name: {
column_names: 'contacts.name'
},
customers: {
joins_table: :customer,
column_names: 'contacts.name',
filters: { contact_type: 'customer' }
},
suppliers: {
joins_table: :supplier,
column_names: 'contacts.name',
filters: { contact_type: 'supplier' }
},
tags: {
tagged_with: true
}
}.with_indifferent_access
def self.search(field, query)
field = QUICK_SEARCH_FIELDS[field]
contact = all
contact = contact.joins(field[:joins_table]) if field[:joins_table]
contact = contact.where(field[:filters]) if field[:filters]
contact = contact.where("#{field[:column_names]} LIKE ?", "%#{query}%") if field[:column_names]
contact = contact.tagged_with(query) if field[:tagged_with]
contact
end
form
<div class='panel' id='panel-search'>
<%= form_tag contacts_path, method: :get do %>
<div class='l-inline-row-block'>
<div class='l-inline-col width_120px'>
<%= select_tag(:qs, options_for_select(Contact::QUICK_SEARCH_FIELDS.keys(), selected: params[:qs]), class: 'customSelect') %>
</div>
<div class='l-inline-col'>
<%= search_field_tag :search, params[:search] %>
</div>
<div class='l-inline-col' style='width: 100px;'>
<%= submit_tag submit_text %>
</div>
</div>
<% end %>
</div>
you may need to make view adjustments and you cannot just use the search term/query for all fields:
1.make sure the fields inside the form in your view are all the same names of the columns in the Contact model that need to be searched
2.add a hidden field inside each form so you can determine which search this is (there is another option but this one is less work)
3.change the collection_select where user can only select one field to select_tag in order to not mess up query building
every field that is filled will pass a value- you can build a hash including column/form-field entered and their value e.g { contact_type: "value1", prospect_strength: "value2" }
after that, you would need to build a query using that hash and query the DB
this would look like so:
In your view:
add this in the advanced search form
<%= hidden_field_tag :search_type, :advanced %>
and in your normal search add this
<%= hidden_field_tag :search_type, :normal %>
In your model:
def self.advanced_search(values_by_column_name) # values_by_column_name is a hash passed from the controller
tag_list = values_by_column_name.delete("tag_list")
sql_query = values_by_column_name.keys.map { |column| "#{column} LIKE :#{column}" }
sql_query = sql_query.join(" OR ")
values_by_column_name = values_by_column_name.transform_values { |value| "%#{value}%" }.symbolize_keys
relation = Contact.where(sql_query, values_by_column_name)
relation = relation.tagged_with(tag_list) if tag_list
relation
end
in your controller:
ADVANCED_SEARCH_FIELDS = [
:contact_type,
:prospect_strength,
:customer_account_id,
:supplier_account_id,
:company_name,
:name,
:title,
:postcode,
:created_at,
:updated_at,
{tag_list: []},
:assigned_to,
:obsolete,
]
def index
#per_page = params[:per_page] || 20
#tags = ActsAsTaggableOn::Tag.all
if advanced_search?
#contacts = Contact.advanced_search(advanced_search_params)
elsif normal_search?
#contacts = Contact.search(params[:qs], params[:search])
else
#contacts = Contact.all
end
#contacts = #contacts.order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: #per_page)
end
def advanced_search?
params[:search_type] == "advanced" && advanced_search_params.any?
end
def normal_search?
params[:search_type] == "normal" && params[:search].present?
end
def advanced_search_params
#_advanced_search_params ||= params.permit(ADVANCED_SEARCH_FIELDS).select { |_, v| v.present? }.to_h
end
I am trying to make a nested form with two types of movements: mov_principal and mov_egreso, of which I try it through a main movement
these are the models
mov_principal.rb
class MovPrincipal < ActiveRecord::Base
self.table_name = 'mov_principal'
has_one :mov_ingreso, :class_name => 'MovIngreso'
accepts_nested_attributes_for :mov_ingreso
belongs_to :tipo_concepto, :class_name => 'TipoConcepto', :foreign_key => :id_tipo
belongs_to :banco
end
mov_ingreso
class MovIngreso < ActiveRecord::Base
self.table_name = 'mov_ingreso'
belongs_to :mov_principal , :class_name => 'MovPrincipal'
accepts_nested_attributes_for :mov_principal, :allow_destroy => true
has_many :puntos, :class_name => 'Punto'
end
the controller mov_principal_controller.rb
class MovPrincipalsController < ApplicationController
before_action :set_movprincipal, except: [:index,:new,:create]
before_action :set_tipooper
def index
#mov_principals = MovPrincipal.all.order("referencia DESC")
end
def new
#mov_principal = MovPrincipal.new
if params[:tipooper] == '0'
#mov_ingreso = #mov_principal.build_mov_ingreso
else
# #gastos = Gasto.new
# #mov_egresos = #mov_principal.build_mov_egresos
#mov_egresos = #mov_principal.mov_egresos.build
#gasto = #mov_egresos.build_gasto
end
end
def create
if #tipooper == '0'
#mov_principal = current_user.mov_principals.new(movingreso_params)
else
#mov_principal = current_user.mov_principals.new(movgastos_params)
end
if #mov_principal.save
render :show
else
render :new
end
end
private
def set_movprincipal
#mov_principal = MovPrincipal.find(params[:id])
end
def set_tipooper
#tipooper = params[:tipooper]
end
def movgastos_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,
mov_egreso_attributes: [:id,:mov_principal_id,:haber, :gasto_id,
gasto_attributes: [Gasto.attribute_names.map(&:to_sym).push(:_destroy)]] )
end
def movingreso_params
params.require(:mov_principal).permit(:id,:referencia,:id_tipo,:banco_id,:user_id,:_destroy,
mov_ingreso_attributes: [:id,:debe,:mov_principal_id,:_destroy ])
end
end
And the view
_formingreso.html.erb
<%=form_for(#mov_principal, :html => {:class => 'form-horizontal'}) do |f| %>
<% #mov_principal.errors.full_messages.each do |message| %>
<div class="be-red white top-space">
* <%= message %>
</div>
<% end %>
<div class="form-group row">
<label class="col-sm-2 col-form-label"> <%= f.label :referencia, "N° Referencia" %> </label>
<div class="col-sm-10">
<%= f.text_field :referencia, class: 'form-control', placeholder: "N° DE REFERENCIA" %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_tipo, "Tipo" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:id_tipo, TipoConcepto.where(:forma => "1"), :id, :tipo,{:prompt => "SELECCIONE EL TIPO DE INGRESO"}, {class: 'custom-select'}) %>
</div>
</div>
<div class="form-group row" >
<label class="col-sm-2 col-form-label"> <%= f.label :id_banco, "Banco" %> </label>
<div class="col-sm-10">
<%= f.collection_select(:banco_id, Banco.all, :id, :nombre,{:prompt =>"SELECCIONE EL BANCO"} ,{class: 'custom-select'} ) %>
</div>
</div>
<div class="form-group row" >
<%= f.fields_for :mov_ingreso_attributes do |ingreso| %>
<label class="col-sm-2 col-form-label"> <%= ingreso.label :debe, "Monto" %> </label>
<div class="col-sm-10">
<%= ingreso.text_field :debe, class: 'form-control' , placeholder: "MONTO DE INGRESO" %>
</div>
<% end %>
The page loads me, it saves me the mov_principal data but it does not save me the mov_ingreso data and the error I find in the console is Unpermitted parameter: :mov_ingreso_attributes
Please do not send me links from the official rails page on how to work strong_parameter blah blah blah I have hours researching and searching in forums trying solutions and even read in a blog about an error that has rails when updating version, and had to create a initializer of strong_parameter, I did it and nothing anyway I show it here just in case it has any relevance
/initializers/strong_parameter.rb
if Rails.env.test?
ActionController::Parameters.action_on_unpermitted_parameters = :raise
end
Thank you all!!
Please don't flag this as duplicate. I've already reviewed the other similar questions and mine is different.
I have an issue where some of the users that input their addresses manage to create duplicate CartAddress records.
My database structure includes a Cart model and CartAddress model.
The Cart model looks something like this:
class Cart < ApplicationRecord
has_many :cart_addresses, -> { order(address_type: :asc) }, inverse_of: :cart, dependent: :destroy
accepts_nested_attributes_for :cart_addresses, allow_destroy: true
end
My CartAddress model looks like this:
class CartAddress < ApplicationRecord
belongs_to :cart
validates :first_name, presence: true
validates :last_name, presence: true
validates :email, presence: true
validates :telephone, presence: true
validates :address_line_one, presence: true
validates :city, presence: true
validates :country, presence: true
validates :state, presence: true
validates :zip_code, presence: true
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
end
When the user loads the cart page:
def index
#bunch of init code here
#more here
#exists = true
if #cart.cart_addresses.count == 0
#exists = false
2.times { #cart.cart_addresses.build(country: "United States", state: "Alabama")}
end
end
Then when I create/update:
def update_addresses
#countries = Country.all
#states = State.all
#cart = Cart.find(params[:cart][:id])
if params[:cart][:cart_addresses_attributes]["0"][:address_type] == "Billing" and params[:cart][:cart_addresses_attributes]["1"][:address_type] == "Shipping"
#cart.update(params.require(:cart).permit(cart_addresses_attributes: [:id, :address_type, :first_name, :last_name, :email, :telephone, :address_line_one, :address_line_two, :city, :zip_code, :country, :state]))
#bunch of other code
end
Here is my partial that renders the form
<%= form_for(cart, :remote => true, :url => update_cart_addresses_path, :html => {:class => 'addresses-class', :id => 'cart-addresses', :autocomplete => :off}) do |u| %>
<% billing = true %>
<% state = 0 %>
<%= u.hidden_field :id %>
<% offset_two = true %>
<% if #exists == true %>
<%= u.fields_for :cart_addresses do |b| %>
<%= b.hidden_field :address_type %>
<% if billing == true %>
<div class="col-xs-12">
<h4>Billing Address</h4>
<% billing = false %>
</div>
<% else %>
<div class="col-xs-12 pad-top-15 checkout-section-padding">
<h4>Shipping Address</h4>
<input type="checkbox" id="same-as-billing" name="same_as_billing" value="1" onclick="toggleShippingAddress(this);">Same as Billing?
</div>
<% end %>
<div class="address">
<div class="col-xs-6">
<%= b.label :first_name %><span class="required-field">*</span>
<%= b.text_field :first_name, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''}%>
</div>
<div class="col-xs-6">
<%= b.label :last_name %><span class="required-field">*</span>
<%= b.text_field :last_name, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :email %><span class="required-field">*</span>
<%= b.email_field :email, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :telephone %><span class="required-field">*</span>
<%= b.text_field :telephone, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :address_line_one %><span class="required-field">*</span>
<%= b.text_field :address_line_one, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.text_field :address_line_two, class: 'checkout-addr-text-field', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :city %><span class="required-field">*</span>
<%= b.text_field :city, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :country %><span class="required-field">*</span>
<%= b.select(:country, countries.all.collect {|a| [a.name]}, {:prompt => "Select A Country"}, :onchange => "setStates(#{state});", class: 'checkout-country') %>
</div>
<div class="col-xs-6 pad-top-15">
<div id="<%= "state_" + state.to_s %>">
<%= b.label :state %><span class="required-field">*</span>
<%= b.text_field :state, class: 'checkout-addr-text-field' %>
</div>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :zip_code%><span class="required-field">*</span>
<%= b.text_field :zip_code, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<% state = state + 1 %>
</div>
<% end %>
<% else %>
<%= u.fields_for :cart_addresses do |b| %>
<% if billing == true %>
<div class="col-xs-12">
<h4>Billing Address</h4>
<% billing = false %>
<%= b.hidden_field :address_type, value: "Billing" %>
</div>
<% else %>
<div class="col-xs-12 pad-top-15 checkout-section-padding">
<h4>Shipping Address</h4>
<input type="checkbox" id="same-as-billing" name="same_as_billing" value="1" onclick="toggleShippingAddress(this);">Same as Billing?
<%= b.hidden_field :address_type, value: "Shipping" %>
</div>
<% end %>
<div class="address">
<div class="col-xs-6">
<%= b.label :first_name %><span class="required-field">*</span>
<%= b.text_field :first_name, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-6">
<%= b.label :last_name %><span class="required-field">*</span>
<%= b.text_field :last_name, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :email %><span class="required-field">*</span>
<%= b.email_field :email, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :telephone %><span class="required-field">*</span>
<%= b.text_field :telephone, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :address_line_one %><span class="required-field">*</span>
<%= b.text_field :address_line_one, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.text_field :address_line_two, class: 'checkout-addr-text-field', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :city %><span class="required-field">*</span>
<%= b.text_field :city, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<div class="col-xs-12 pad-top-15">
<%= b.label :country %><span class="required-field">*</span>
<%= b.select(:country, countries.all.collect {|a| [a.name]}, {:prompt => "Select A Country"}, :onchange => "setStates(#{state});", class: 'checkout-country') %>
</div>
<div class="col-xs-6 pad-top-15">
<div id="<%= "state_" + state.to_s %>">
<%= b.label :state %><span class="required-field">*</span>
<%= b.text_field :state, class: 'checkout-addr-text-field' %>
</div>
</div>
<div class="col-xs-6 pad-top-15">
<%= b.label :zip_code %><span class="required-field">*</span>
<%= b.text_field :zip_code, class: 'checkout-addr-text-field required', :data => {:hj_whitelist => ''} %>
</div>
<% state = state + 1 %>
</div>
<% end %>
<% end %>
<% end %>
<div class="col-xs-12 pad-top-15">
<button id="update-checkout-addresses-btn" class="checkout-addresses-submit-btn btn btn-primary btn-sm" onclick="submitCheckoutAddressesForm(this);" type="button">Update Addresses</button>
</div>
When creating new address records the form is submitted without an id. When editing the records a id is submitted. Somehow it appears that the form is being submitted more than once although I do have javascript disabling the form upon submission. How should I handle this in the controller to prevent this error from happening? Or fix my view partial?
UPDATE
Here is my JS
function submitCheckoutAddressesForm(element){
element.disabled = true;
var e = document.getElementById("same-as-billing")
sameAsBillingCheckout(e);
$(e).closest("form").submit();
}
The below function makes sure that all the elements are the same in the form if a checkbox "Shipping Address Same As Billing" is selected. The reason I am having to clone the element and copy it into the shipping addresses is because the element type has the ability to change due to other javascript. I figured this would be the safest way of handling this event just to ensure that the proper elements were submitted in the form. I don't see that this should effect the duplicate records being created.
function sameAsBillingCheckout(element){
if(element.checked == true){
var billing = ["#cart_cart_addresses_attributes_0_first_name", "#cart_cart_addresses_attributes_0_last_name", "#cart_cart_addresses_attributes_0_email", "#cart_cart_addresses_attributes_0_telephone",
"#cart_cart_addresses_attributes_0_address_line_one", "#cart_cart_addresses_attributes_0_address_line_two", "#cart_cart_addresses_attributes_0_country", "#cart_cart_addresses_attributes_0_state", "#cart_cart_addresses_attributes_0_city", "#cart_cart_addresses_attributes_0_zip_code"]
var shipping = ["#cart_cart_addresses_attributes_1_first_name", "#cart_cart_addresses_attributes_1_last_name", "#cart_cart_addresses_attributes_1_email", "#cart_cart_addresses_attributes_1_telephone",
"#cart_cart_addresses_attributes_1_address_line_one", "#cart_cart_addresses_attributes_1_address_line_two", "#cart_cart_addresses_attributes_1_country", "#cart_cart_addresses_attributes_1_state", "#cart_cart_addresses_attributes_1_city", "#cart_cart_addresses_attributes_1_zip_code"]
for(i = 0; i < billing.length; i++){
$(shipping[i]).val($(billing[i]).val());
if(billing[i] == "#cart_cart_addresses_attributes_0_country"){
$("#cart_cart_addresses_attributes_1_state").remove();
var e = document.getElementById("cart_cart_addresses_attributes_0_state");
var cln = e.cloneNode(true);
cln.name = "cart[cart_addresses_attributes][1][state]";
cln.id = "cart_cart_addresses_attributes_1_state";
var stateDiv = document.getElementById("state_1");
stateDiv.appendChild(cln);
}
}
}
}
This code below does the same as the javascript above. It's just submitting the form after the user finishes typing if the form isn't disabled.
$(function(){
//create one instance for handler:
var myHandler = function(e){
var sAB = document.getElementById("same-as-billing").checked;
var ready = true;
//LOOPS THROUGH ALL THE TEXT FIELDS
$('.checkout-addr-text-field').each(function (){
//IF SAME AS BILLING CHECKBOX SELECTED
if(sAB == true){
//if the field is disabled or the field includes _0_ (means its a billing address field) and the id is not the optional field and the value isn't blank then dont submit the form.
if(this.disabled || this.id.indexOf("_0_") !== -1 && this.id !=
"cart_cart_addresses_attributes_0_address_line_two" && this.value == ""){
ready = false;
}
}else{ // IF SAME AS BILLING CHECKBOX NOT SELECTED
if(this.disabled || this.id !=
"cart_cart_addresses_attributes_0_address_line_two" && this.id !=
"cart_cart_addresses_attributes_1_address_line_two" && this.value == ""){
ready = false;
}
}
});
if(ready == true){
var e = document.getElementById("same-as-billing")
sameAsBillingCheckout(e);
$(e).closest("form").submit();
$("#cart-addresses :input").attr("disabled", true);
}
};
$(document).on('keyup', '.checkout-addr-text-field', debounce(function(e){
myHandler(e);
}, 1700));
$(document).on('change', '#cart_cart_addresses_attributes_0_state', function(e){
myHandler(e);
});
$(document).on('change', '#cart_cart_addresses_attributes_1_state', function(e){
myHandler(e);
});
$(document).on('change', '#cart_cart_addresses_attributes_0_state', function(e){
myHandler(e);
});
$(document).on('click', '#same-as-billing', function(e){
if(this.checked){
myHandler(e);
}
});
});
I am writing a custom FormBuilder in Rails and I get the above error at "around line 14" (<%= f.text_field :name, autofocus: true %>) of the view.
My FormBuilder:
class FoundationFormBuilder < ActionView::Helpers::FormBuilder
delegate :content_tag, to: :#template
delegate :label_tag, to: :#template
def text_field(method, options = {})
options[:label] ||= "#{method.to_s}".humanize
options[:class] ||= ""
field_errors = object.errors[method].join(', ') unless object.errors[method].blank?
error_class = "error" if field_errors
error_class ||= ""
label_tag("#{#object_name}[#{method}]", "#{options[:label]}", class: error_class) do
label << #template.send(text_field_tag("#{#object_name}[#{method}]", nil, class: "error_class #{options[:class]}"))
# label << (content_tag(:small, field_errors.humanize, class: error_class)) if field_errors
label.html_safe
end
end
end
In my view:
<%= form_for(#message, url: contact_us_path, builder: FoundationFormBuilder) do |f| %>
<!--<%= f.label :name %>-->
<%= f.text_field :name, autofocus: true %>
<!--<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :comment %>
<%= f.text_area :comment, rows: 10 %>
<%= f.submit "Send", class: "button round right" %>-->
<% end %>
Here is the application trace:
app/helpers/foundation_form_builder.rb:13:in `block in text_field'
app/helpers/foundation_form_builder.rb:3:in `label_tag'
app/helpers/foundation_form_builder.rb:12:in `text_field'
app/views/contact_us/new.html.erb:14:in `block in _app_views_contact_us_new_html_erb___968573049544088412_70132699754860'
app/views/contact_us/new.html.erb:12:in `_app_views_contact_us_new_html_erb___968573049544088412_70132699754860'
As far as I can tell I am passing the arguments to the label_tag since I presume this is what is causing the error. What am I actually doing wrong?
Update:
I think it has to do with the method beign passed as text_field to a label, but I'm not sure. Still scratching my head.
The issue was trying to append to label when I had not initialised it previously.
What I wanted to achieve was the following:
<form>
<div class="row">
<div class="large-6 columns">
<label class="error">Error
<input type="text" class="error" />
</label>
<small class="error">Invalid entry</small>
</div>
<div class="large-6 columns error">
<label>Another Error
<input type="text" />
</label>
<small class="error">Invalid entry</small>
</div>
</div>
<textarea class="error" placeholder="Message..."></textarea>
<small class="error">Invalid entry</small>
</form>
As seen here Zurb - Foundation 5 Forms
Which has been done as follows:
FormBuilder:
class FoundationFormBuilder < ActionView::Helpers::FormBuilder
delegate :content_tag, to: :#template
delegate :label_tag, to: :#template
def text_field(method, options = {})
options[:label] ||= "#{method.to_s}".humanize
options[:class] ||= ""
field_errors = object.errors[method].join(', ') unless object.errors[method].blank?
options[:class] << "error" if field_errors
options = objectify_options(options)
options.delete(:object)
label = lambda do
label_tag("#{#object_name}[#{method}]", "#{options[:label]}", class: "#{'error' if field_errors}") do
label = "#{options[:label]}"
label << #template.send('text_field_tag', "#{#object_name}[#{method}]", nil, options)
label.html_safe
end
end
error_messages = lambda do
content_tag(:small, field_errors.humanize, class: "error") if field_errors
end
"#{label.call} #{error_messages.call}".html_safe
end
def text_area(method, options = {})
options[:label] ||= "#{method.to_s}".humanize
options[:class] ||= ""
field_errors = object.errors[method].join(', ') unless object.errors[method].blank?
options[:class] << "error" if field_errors
options = objectify_options(options)
options.delete(:object)
label = lambda do
label_tag("#{#object_name}[#{method}]", "#{options[:label]}", class: "#{'error' if field_errors}") do
label = "#{options[:label]}"
label << #template.send('text_area_tag', "#{#object_name}[#{method}]", nil, options)
label.html_safe
end
end
error_messages = lambda do
content_tag(:small, field_errors.humanize, class: "error") if field_errors
end
"#{label.call} #{error_messages.call}".html_safe
end
end
View:
<%= form_for(#message, url: contact_us_path, builder: FoundationFormBuilder) do |f| %>
<%= f.text_field :name %>
<%= f.text_field :email %>
<%= f.text_area :comment, rows: 10 %>
<%= f.submit "Send", class: "button round right" %>
<% end %>
It has achieved the result, but is this a safe way to achieve what I wanted?
I met very strange problem. I have Timetable model and try to write my custom validation. So, now i'm just trying to add test error for field to make sure that everything is ok. But it doesn't work. So, i try to update object of Timetable model but when i don't use my test custom validation everything works perfect. Otherwise i get such error:
NoMethodError in Timetables#update
undefined method `map' for nil:NilClass
32:
33: <div class="controls">
34: <%= f.select( :curriculum_id,
35: options_for_select( #subjects_with_curriculums,
36: #tt.curriculum_id ),
37: { :include_blank => true }) %>
38: </div>
Here is my model:
# == Schema Information
#
# Table name: timetables
#
# id :integer not null, primary key
# curriculum_id :integer
# school_class_id :integer
# tt_day_of_week :string(255)
# tt_number_of_lesson :integer
# tt_room :string(255)
# tt_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Timetable < ActiveRecord::Base
belongs_to :curriculum
belongs_to :school_class
has_many :lessons
validates :school_class_id, :presence => { :message => "should exist" }
validates :tt_day_of_week,
:presence => true,
:inclusion => { :in => %w(Mon Tue Wed Thu Fri) }
validates :tt_number_of_lesson,
:presence => true,
:inclusion => {
:in => 1..9,
:message => "should have 1..9 symbols"
}
validates :tt_room,
:length => {
:maximum => 3,
:message => "should have 3 symbols"
},
:allow_blank => true
validates :tt_type,
:inclusion => { :in => ["Primary lesson", "Extra"] },
:allow_blank => true
validate :test
def test
errors.add(:tt_number_of_lesson, "test")
end
end
My controller:
# encoding: UTF-8
class TimetablesController < ApplicationController
...
def edit
#types_of_lesson = collect_types_of_lesson
#tt = Timetable.find( params[:id] )
#subjects_with_curriculums = collect_subjects_with_curriculums( #tt.school_class )
end
def update
#tt = Timetable.find( params[:id] )
if #tt.update_attributes( params[:timetable] )
flash[:success] = "Расписание успешно обновлено!"
redirect_to timetables_path
else
flash.now[:error] = #tt.errors.full_messages.to_sentence :last_word_connector => ", ",
:two_words_connector => ", "
render 'edit'
end
end
private
# Collecting subjects names for school class and curriculum_id for each subject.
def collect_subjects_with_curriculums( school_class )
subjects = school_class.curriculums.collect do |c|
[ c.qualification.subject.subject_name, c.id ]
end
end
def timetable_for_class_with_existance_data( school_class )
return [] if Timetable.all.empty?
Timetable.select do |t|
( t.school_class.class_code == school_class.class_code ) and
not ( t.tt_room.blank? ) and not ( t.tt_type.blank? ) and
not ( t.curriculum_id.nil? )
end.to_a
end
# Return for school class it's timetable.
def timetable_for_class( school_class )
Timetable.select{|t| t.school_class.class_code == school_class.class_code }.to_a
end
def subjects_of_class( school_class )
subjects = school_class.curriculums.collect do |c|
c.qualification.subject.subject_name
end
end
# Return sorted by number of lesson tometable for one day.
def sorted_timetable_for_day( timetable, day )
timetable.select{ |t| t.tt_day_of_week == day }
.sort_by{ |e| e[:tt_number_of_lesson] }
end
# Return russian name for type of lesson.
def collect_types_of_lesson
[ ["Обязательно занятие", "Primary lesson"], ["Электив", "Extra"] ]
end
# Check if timetable already has been created for school class.
def timetable_exists?( school_class )
not timetable_for_class( school_class ).empty?
end
end
My view
<%= form_for #tt, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<%= f.hidden_field :tt_number_of_lesson %>
<%= f.hidden_field :tt_day_of_week %>
<%= f.hidden_field :school_class_id %>
<div class="control-group">
<%= f.label :tt_day_of_week, "Day of the week", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, translate_day_of_week( #tt.tt_day_of_week ),
:class =>"input-xlarge uneditable-input span2" ) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_number_of_lesson, "Number of lesson", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, #tt.tt_number_of_lesson,
:class =>"input-xlarge uneditable-input span1" ) %>
</div>
</div>
<hr/>
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( #subjects_with_curriculums,
#tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_room, "Code of the room", :class => "control-label" %>
<div class="controls">
<%= f.text_field :tt_room, :class => "span2", :maxlength => 3 %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( #types_of_lesson,
#tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
<%= f.submit "Update", :class => "btn btn-large btn-warning" %>
<% end %>
<% end %>
When i remove:
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( #subjects_with_curriculums,
#tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( #types_of_lesson,
#tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
I can view my test error. I can't figure what is going on.
You say this in your update controller:
render 'edit'
That simply tells Rails to render the edit template, it doesn't run any of the code associated with the edit controller, it simply renders edit.html.erb in the current context.
From the Layouts and Rendering in Rails Guide:
2.2.2 Rendering an Action’s View
[some stuff about render 'x', render :x, and render :action => :x being the same...]
Using render with :action is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before calling render.
Pay particular attention to the last sentence:
Any instance variables that you require in the view must be set up in the current action before calling render.
You're setting #subjects_with_curriculums in the edit controller but using the edit view from the update controller. The result is that #subjects_with_curriculums is nil when edit.html.erb tries to use it when update tries to render the edit view.
You'll need to set #subjects_with_curriculums in your update controller, you might need #types_of_lesson as well.