I guess I did a mess with JQuery and my Rails practice, I intend to get two parameters from a 'form_tag' and then render a calculation result made in my controller inside a '' in a view, I get the result in the Network view (Chrome developer tools) but nothing is rendered in the . Here is the code related:
Route:
get '/calculator', to: 'users#bmi_calc'
users_controller.rb:
def bmi_calc
bmi_table = {
"Very severely underweight" => { from: 0.0, to: 15.0 },
"Severely underweight" => { from: 15.1, to: 16.0 },
"Underweight" => { from: 16.1, to: 18.5 },
"Normal (healthy weight)" => { from: 18.51, to: 25.0 },
"Overweight" => { from: 25.1, to: 30.0 },
"Obese class I (moderately obese)" => { from: 30.1, to: 35.0 },
"Obese class II (severely obese)" => { from: 35.1, to: 40.0 },
"Obese class III (very severely obese)" => { from: 40.1, to: 60.0 },
"Pure fat factor" => { from: 60.1, to: 100.0}
}
weight = params[:mass].to_f
height = params[:height].to_f
if weight > 0 && height > 0
resultado = ''
#bmi = weight / height ** 2
bmi_table.each do |advice, range|
if (#bmi > range[:from]) && (#bmi < range[:to])
resultado = advice
end
end
respond_to do |format|
format.json { render json: {resultado: resultado} }
end
else
redirect_to current_user
end
end
users.js.erb:
$(document).ready( function(){
$("#calculator-img").click( function(){
$.getJSON('/calculator', function(data) {
var res = data.resultado;
$("#bmi-result").html(res);
});
});
});
users/show.html.erb:
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1><%= #user.name %></h1>
</section>
<section class="bmi_form">
<%= render 'bmi_form' %>
</section>
<div id="bmi-result">
</div>
</aside>
<div class="col-md-6">
<section class="mid_section">
<p>Some text</p>
<h2>BMI standard table</h2>
<%= image_tag "BMItable.png", alt: "BMI stardard table" %>
</section>
</div>
</div>
_bmi_form.html.erb:
<%= form_tag calculator_path, method: "get", remote: true, class: "navbar-left" do %>
<%= label_tag :mass, "Your mass (weight) in Kg" %>
<%= number_field_tag :mass, params[:mass], step: 0.01, class: "form-control" %>
<%= label_tag :height, "Your height in meters" %>
<%= number_field_tag :height, params[:height], step: 0.01, class: "form-control" %>
<%= image_submit_tag("BMI.gif", id: "calculator-img") %>
<% end %>
And finally this is what I get in the Chrome developers tools:
Plese help me understand what I am doing wrong. Thanks
(This is the challenge I intended to solve: https://gist.github.com/JonaMX/d29a754ae625664b0cf7
In the end I delivered but I had to render a new page with the result... Not pretty at all)
You need to bind a handler function to your form's ajax request.
First add an id to your form:
<%= form_tag calculator_path, method: "get", remote: true, class: "navbar-left", id: "bmi-form" do %>
<%= label_tag :mass, "Your mass (weight) in Kg" %>
<%= number_field_tag :mass, params[:mass], step: 0.01, class: "form-control" %>
<%= label_tag :height, "Your height in meters" %>
<%= number_field_tag :height, params[:height], step: 0.01, class: "form-control" %>
<%= image_submit_tag("BMI.gif", id: "calculator-img") %>
<% end %>
Then change your javascript to something like this:
$(document).ready( function(){
$("#bmi-form").on( "ajax:success", function(evt, data, status, xhr){
var res = data.resultado;
$("#bmi-result").html(res);
});
});
For more information see http://guides.rubyonrails.org/working_with_javascript_in_rails.html
Can try once this code
$(document).ready( function(){
$("#calculator-img").click( function(){
$.getJSON('/calculator', function(data) {
var res = $.parseJSON(data);
$("#bmi-result").html(res.resultado);
});
});
});
For more information see https://boxoverflow.com/get-json-jquery-ajax/
Related
I'm learning Turbo Frames and Streams + Stimulus so it's possible I'm not 100% on track. I have a form for creating a new object, but within the form I'd like to have a select component that will display certain fields depending on the selection. It's important to note that due to this, I do not want to submit the form until the user has made this selection.
This is what I have:
_form.html.erb
<div class="form-group mb-3">
<%= form.label :parking, class: 'form-label' %>
<%= form.number_field :parking, class: 'form-control' %>
</div>
<%= turbo_frame_tag "turbo_transactions" do %>
<%= render 'property_transactions' %>
<% end %>
_property_transactions.html.erb
<div class="form-group mb-3" data-controller="property-transaction">
<%= label_tag :property_transactions, 'Property in:', class: 'form-label' %>
<%= select_tag :property_transactions, options_for_select(#property_transactions.collect {|p| [p.name, p.id]}), { data:
{ action: "property-transaction#redraw", property_transaction_target: 'transaction', turbo_frame: 'turbo_transactions' },
class: 'form-control', prompt: '', autocomplete: 'off' } %>
</div>
<% if #property_transaction %>
<%= turbo_frame_tag #property_transaction.en_translation_key do %>
<div class="form-group mb-3">
<%= render #property_transaction.en_translation_key %>
</div>
<% end %>
<% end %>
property_transaction_controller.js
import { Controller } from "#hotwired/stimulus";
import Rails from "#rails/ujs";
export default class extends Controller {
static targets = [ "transaction" ];
redraw() {
const params = { property_transaction: this.transaction };
Rails.ajax({
type: 'post',
dataType: 'json',
url: "/set_property_transaction",
data: new URLSearchParams(params).toString(),
success: (response) => { console.log('response', response) }
});
}
get transaction() {
return this.transactionTarget.value;
}
}
property_controller.rb
def set_property_transaction
respond_to do |format|
format.json
format.turbo_stream do
if #property_transactions
#property_transaction = #property_transactions.select { |p| p.id == property_transaction_params }
else
#property_transaction = PropertyTransaction.find(property_transaction_params)
end
end
end
end
set_property_transaction.turbo_stream.erb
<%= turbo_stream.replace #property_transaction.en_translation_key %>
_rent.html.erb
<%= turbo_frame_tag "rent" do %>
<!-- some input fields -->
<% end %>
_rent_with_option_to_buy.html.erb
<%= turbo_frame_tag "rent-with-option-to-buy" do %>
<!-- other input fields -->
<% end %>
_sale.html.erb
<%= turbo_frame_tag "sale" do %>
<!-- more input fields -->
<% end %>
When selecting the option, this error happens:
Started POST "/set_property_transaction" for ::1 at 2022-09-07 19:49:03 -0600
Processing by PropertiesController#set_property_transaction as JSON
Parameters: {"property_transaction"=>"2"}
Completed 406 Not Acceptable in 223ms (ActiveRecord: 0.0ms | Allocations: 1879)
ActionController::UnknownFormat (PropertiesController#set_property_transaction is missing a template for this request format and variant.
request.formats: ["application/json", "text/javascript", "*/*"]
request.variant: []):
My understanding to this is that I'm missing the set_property_translation template, but I do have it. Not sure what else could I do to make it recognizable.
Les Nightingill's comment definitely sent me in the right direction. I'll put the changes needed here.
_property_transactions.html.erb
<div class="form-group mb-3" data-controller="property-transaction">
<%= label_tag :property_transactions, 'Propiedad en:', class: 'form-label' %>
<%= select_tag :property_transactions, options_for_select(#property_transactions.collect {|p| [p.name, p.id]}), { data:
{ action: "property-transaction#redraw", property_transaction_target: 'transaction', turbo_frame: "turbo_transactions" },
class: 'form-control', prompt: '', autocomplete: 'off' } %>
</div>
<%= turbo_frame_tag "dynamic_fields" %>
property_transaction_controller.js
import { Controller } from "#hotwired/stimulus";
import { post } from "#rails/request.js";
export default class extends Controller {
static targets = [ "transaction" ];
async redraw() {
const params = { property_transaction: this.transaction };
const response = await post("/set_property_transaction", {
body: params,
contentType: 'application/json',
responseKind: 'turbo-stream'
});
if (response.ok) {
console.log('all good', response); // not necessary
}
}
get transaction() {
return this.transactionTarget.value;
}
}
set_property_transaction.turbo_stream.erb
<%= turbo_stream.update "dynamic_fields" do %>
<%= render partial: #property_transaction.en_translation_key %>
<% end %>
I am writing a simple web site that requires cascade select tags. The selected option in the first select tag, floor_id, changes the options in the second select tag, space_id. I have put these 2 selects into 2 separated forms. The problem is, the onchange event in the select floor_id does not trigger the json changing the options in the second select tag but the submit button does. Could some gurus tell me how to fix it? Thanks a ton!
Here is my code in app/controllers/spaces_controller.rb
class SpacesController < ApplicationController
def index
#floors = Floor.all.order(:name)
#spaces = Space.all.order(:name)
end
def list
#floor_id = params[:floor_id]
#spaces = Space.includes(:maps).where( \
"maps.floor_id = ? OR 0 = char_length(?)", \
#floor_id.to_i, \
#floor_id.to_s, \
).references(:map)
render :partial => 'list', :object => #spaces
end
...
end
File app/assets/javascripts/spaces.js.coffee
$(document).ready ->
$("#category").on("ajax:success", (e, data, status, xhr) ->
$("#space_list").html xhr.responseText
).on "ajax:error", (e, xhr, status, error) ->
$("#space_list").html "<option value=''>Error</option>"
File app/assets/javascripts/defaults.js
function go_to_uri
( iObject
, iId
, iAction
)
{
if (!iId || iId.length === 0 || iId === "" || typeof iId == 'undefined' || !/[^\s]/.test(iId) || /^\s*$/.test(iId) || iId.replace(/\s/g,"") == "")
return false;
this.document.location.href = iObject + "/" + iId + "/" + iAction;
return false;
}
File app/views/spaces/index.html.erb
<h1>Spaces</h1>
<%= form_tag list_spaces_url, method: :post, remote: true, id: 'category' do |f| %>
<p>
<%= label_tag :floor_id, 'Floor' %>
<%= select_tag \
:floor_id, \
options_from_collection_for_select(#floors, :id, :name), \
include_blank: true, \
onchange: '$(this).parent(\'form\').submit();' %>
</p>
<%= submit_tag %>
<% end %>
<%= form_tag 'nil', method: :get do |f| %>
<%= label_tag :space, 'Space' %>
<span id="space_list"><%= render 'list' %></span>
<%= button_tag type: \
'button', \
onclick: 'go_to_uri("spaces", this.form.space.value, "map")' \
do %>
Show Map
<% end %>
<% end %>
file app/views/spaces/list.html.erb
<%= select_tag \
:space_id, \
options_from_collection_for_select(#spaces, :id, :name), \
include_blank: true, \
onchange: 'go_to_uri("spaces", this.value, "map")' %>
I have rewrote the onchange event with coffee script and now it is working.
File app/assets/javascripts/spaces.js.coffee
$(document).ready ->
$("#space_category").on("ajax:success", (e, data, status, xhr) ->
$("#space_list").html xhr.responseText
).on "ajax:error", (e, xhr, status, error) ->
$("#space_list").html "<option value=''>Error</option>"
$(".space_category").change ->
$("#space_category").submit()
File app/views/spaces/index.html.erb
<h1>Spaces</h1>
<%= form_tag list_spaces_url, method: :post, remote: true, id: 'space_category' do |f| %>
<p>
<%= label_tag :floor_id, 'Floor' %>
<%= select_tag \
:floor_id, \
options_from_collection_for_select(#floors, :id, :name), \
include_blank: true, \
class: 'space_catefory' %>
</p>
<%= submit_tag %>
<% end %>
<%= form_tag 'nil', method: :get do |f| %>
<%= label_tag :space, 'Space' %>
<span id="space_list"><%= render 'list' %></span>
<%= button_tag type: \
'button', \
onclick: 'go_to_uri("spaces", this.form.space.value, "map")' \
do %>
Show Map
<% end %>
<% end %>
I am new to RoR and AJAX, jquery etc. I am trying to make an ajax call in a view, but its not happening.
Corresponding controller(product_search_controller,rb) is:
def index
#products = querySolr(params[:q])
#productsProxy = Array.new
if #products != nil
#products.each do |p|
#productsProxy.push(ProductProxy.new(p))
end
else
#productProxy = []
end
#taxons = #productsProxy.map(&:get_taxonomy).compact.uniq
respond_with("Search Results") do |format|
format.js
format.html
format.xml { render :xml => #productsProxy, :only => [:name, :permalink, :description, :mrp], :methods => [:designer, :taxons, :price] }
end
end
Corresponding view(views/product_search/index.hrml.erb) is:
<%= render :partial => 'products', :locals => {:products => #productsProxy, :taxons => #taxons, :scope => self, :scope_type => "Search"} %>
<%= render :partial => 'shared/inf_scroll', :locals => {:url => "?&page=", :total_count => #total_count} %>
/views/product_search/_products.html.erb:
<% if products.empty? %>
<div class="not_found"><%= "No Products found for the selected query. Please try a different search." %></div>
<% elsif params.key?(:keywords) %>
<h3><%= t(:search_results, :keywords => h(params[:keywords])) %></h3>
<% end %>
<% if products.any? %>
<div class="product_rows">
<%= render :partial=> 'product_listing_feature', :locals => {:scope => scope, :scope_type => scope_type} %>
<div id="ql_product"></div>
<%taxons.each do |taxon|%>
<ul class="products" data-hook class="products">
<div class = "product_row">
<h1><%=taxon%></h1>
<% taxonProducts = Array.new %>
<% products.each do |product| %>
<%#ptaxon = product.get_taxonomy%>
<%if #ptaxon == taxon%>
<% taxonProducts.push(product) %>
<% end %>
<% end %>
<div class ="featured_product_list">
<ul class = "featured_products">
<div class = "page">
<%= render :partial=> 'product_listing', :locals=>{:collection=> taxonProducts} %>
</div>
</ul>
</div>
</div>
</ul>
<% end %>
</div>
</div>
<% end %>
i.e it renders another partial _product_listing which has the following script:
<script>
$("document").ready(function(){
$("li#product_<%=product.productId%>").hover(
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "visible");},
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");}
);
$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");
});
hide_sold_out({
url: "<%= sold_out_status_taxons_url(#taxon) %>",
data: {
pids: "<%= collection.map(&:id).join(",") %>"
}
});
</script>
Helper:
var hide_sold_out = function(options){
$.ajax({
url: options["url"],
data: options["data"],
type: 'get',
dataType: 'text',
success: function(data){
pids = data.split(',');
for(var i = 0; i < pids.length; i++) {
if($("li#product_"+pids[i]).children("div.info").children("span.offer.sold").length == 0) {
$("li#product_"+pids[0]).children("div.info").append("<span class='offer sold'></div>");
$("li#product_"+pids[0]).children("div.info").children("div.product_listing_info_hover").children("div.listing_buttons").html("");
}
}
},
error: function(data){
console.log(data);
}
. I tried using the following in /views/product_search/index.js.erb:
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #productsProxy})) %></div></div>")
This didn't work. Then i tried:
<%#taxons.each do |taxon|%>
<%taxonProducts = Array.new%>
<%#productsProxy.each do |product|%>
<%#ptaxon=product.get_taxonomy%>
<%if #ptaxon==taxon%>
<%taxonProducts.push(product)%>
<%end%>
<%end%>
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #taxonProducts})) %></div></div>")
<%end%>
But the AJAX call is not doing what its supposed to do. Please could someone help me debug this. Thanks
These
url: options["url"],
data: options["data"],
should be
url: options.url,
data: options.data,
I am so frustrated. I'm working with Stripe to create a form submission system for payments. Basically, the form makes an AJAX call to Stripe, which gives me a token on success, which I then use to resubmit the form, also through AJAX. If the form is successful, it redirects to a new page, if not, it populates the form with error messages without re-navigation. Here's my form:
<%= form_for([#issue, #issue_order]) do |f| %>
<% if #issue_order.errors.any? %>
<div class="error_messages">
<h2><%= pluralize(#issue_order.errors.count, "error") %> occurred. </h2>
<ul>
<% #issue_order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% f.hidden_field :issue_id %>
<%= f.hidden_field :stripe_card_token %>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="field">
<%= label_tag :card_number, "Credit Card Number " %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_code, "Security Code on Card (CVV) " %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_month, "Card Expiration " %>
<%= select_month nil, {add_month_numbers_true: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year + 15}, {name: nil, id: "card_year"} %>
</div>
<div id="stripe_error"></div>
<div class="actions"><%= f.submit "Purchase Issue", id: "submit_issue_order" %></div>
<% end %>
<div class="errors"></div>
Here is the javascript that handles the form and sets up the stripe information:
var issueOrder;
$(function() {
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
issueOrder.setupForm();
});
var issueOrder = {
setupForm: function() {
$('#new_issue_order').submit(function(e) {
e.preventDefault();
$('#submit_issue_order').attr('disabled', true);
issueOrder.processCard();
return false;
});
},
processCard: function() {
var card;
card = {
number: $('#card_number').val(),
cvc: $('#card_code').val(),
expMonth: $('#card_month').val(),
expYear: $('#card_year').val()
};
Stripe.createToken(card, issueOrder.handleStripeResponse)
},
handleStripeResponse: function(status, response) {
if (status == 200) {
$('#issue_order_stripe_card_token').val(response.id);
// $('#new_issue_order')[0].submit();
$.ajax({
type: "POST",
url: $('#new_issue_order').attr('action'),
data: { "issue_order": {
"stripe_card_token": $('#issue_order_stripe_card_token').val(),
"email": $('issue_order_email').val(),
},
"issue_id": $('#issue_order_issue_id').val()
},
dataType: "script"
}, issueOrder.processOrder);
}
else {
$('#stripe_error').text(response.error.message);
$('input[type=submit]').attr('disabled', false)
}
}
And here is my controller:
def create
charge = Stripe::Charge.create(
:amount => 400,
:currency => "usd",
:card => params['issue_order']['stripe_card_token']
)
if charge['paid'] == true
#issue_order = IssueOrder.new(email: params['issue_order']['email'], issue_id: params['issue_id'])
if #issue_order.save
#pdf_token = #issue_order.pdf_token
PdfMailer.pdf_email(params['issue_order']['email'], #issue_order).deliver
else·
flash[:error] = []
flash[:error].push("Your card was charged, but sadly we were unable to create·
a record in the database. Please contact us for your copy of the issue.")
respond_to do |format|
format.js
end
end
else
# run checks for errors and return error messages
flash[:error] = []
flash[:error].push("There was an error in processing your payment.")
render :json => {success: false}
end
end
Typical stripe setup stuff. Works fine when the stripe order is successfully processed. Well, it did before I hand-rolled the AJAX call, I'm assuming it'd be fine if I threw a respond_to |format| in the success case in the controller that redirected to the success page. However, for the error cases, my controller renders create.js.erb, which looks like this:
console.log('yo');
$('.errors').empty();
errors = xhr.getResponseHeader('X-Flash-Error').split(',');
<% flash[:error].each do |error| %>
$('.errors').append($('<p>' + <%= error %> + '</p>'));
<% end %>
setTimeout(function() {
$('.errors').empty();
}, 3500);
The controller clearly reaches the file and renders it, as evidenced by the logs:
Started POST "/issues/1/issue_orders" for 127.0.0.1 at 2013-11-12 23:33:17 -0500
Processing by IssueOrdersController#create as JS
Parameters: {"issue_order"=>{"stripe_card_token"=>"tok_102vmu2pSkyWUgPAToj334Oa"}, "issue_id"=>"1"}
(0.4ms) BEGIN
(0.4ms) ROLLBACK
Rendered issue_orders/create.js.erb (0.1ms)
["Your card was charged, but sadly we were unable to create \n a record in the database. Please contact us for your copy of the issue."]
Completed 200 OK in 1363ms (Views: 3.9ms | ActiveRecord: 0.8ms)
But NOTHING happens on my page, including the console log! If I don't hand roll the AJAX and use remote: true, it gets even worse -- it recognizes my submit() call as HTML and doesn't know what to do with the format, rendering an Unknown Format error.
Help!
I recently tried to implement a cascading dropdown into my application with this tutorial on petermac.com: http://www.petermac.com/rails-3-jquery-and-multi-select-dependencies/
The tutorial basically talks about doing a cascading dropdown, where every dropdown box is an a separate partial and gets loaded with an jQuery onChange event when the parent select is changed.
Now I got this to work without a problem. But actually my select boxes have quite complicate relationships between them.
So, the form I belongs to a Model called AuditFunction and as the name says is for auditing. Every audit has a source and a target, which can be compared via several commands. The source as well as the target are selected via 3 select boxes. The first box selects the type of database the field is in. The second box selects the table and then the third box selects the field. As the field box can contain thousands of options I tried to implement the cascading dropdown to make it easier for the user to select the field.
To give you an overview, this is what my actions look like:
# new.html.erb
<%= simple_form_for #audit_function do |f| %>
<%= f.input :database_1, :as => :select, :collection => #databases, :include_blank => true %>
<%= render :partial => 'databases_1' %>
<%= render :partial => 'fields_1' %>
<%= f.input :database_2, :as => :select, :collection => #databases, :include_blank => true %>
<%= render :partial => 'databases_2' %>
<%= render :partial => 'fields_2' %>
<% end %>
The javascript for this looks like this:
# jQuery
<script type='text/javascript' charset='utf-8'>
jQuery(function($) {
// when the #country field changes
$("#audit_function_database_1").change(function() {
var database_1 = $('select#audit_function_database_1 :selected').val();
if(database_1 == "") database_1="0";
jQuery.get('/audit_functions/update_database_1_id_select/' + database_1, function(data){
$("#database_1_id").html(data);
})
return false;
});
})
</script>
<script type='text/javascript' charset='utf-8'>
jQuery(function($) {
// when the #country field changes
$("#audit_function_database_2").change(function() {
var database_2 = $('select#audit_function_database_2 :selected').val();
if(database_2 == "") database_2="0";
jQuery.get('/audit_functions/update_database_2_id_select/' + database_2, function(data){
$("#database_2_id").html(data);
})
return false;
});
})
Now I'm only going to show you the partials for database_1_id and field_1_id, but they look the same as database and field 2.
# _databases_1.html.erb
<script type="text/javascript">
jQuery(function($) {
$("#audit_function_database_1_id").change(function() {
var database_1_id = $('select#audit_function_database_1_id :selected').val();
if(database_1_id == "") database_1_id="0";
jQuery.get("/audit_functions/update_field_1_id_select/" + ("<%= params[:id] %>_" + database_1_id), function(data){
$("#field_1_id").html(data);
})
return false;
});
})
</script>
<%= simple_form_for "audit_function" do |f| %>
<% if params[:id] %>
<% if params[:id] == "imp" %>
<%= f.input :database_1_id, collection: AdOriTbl.all.order(ori_filename: :asc).collect{ |a| [a.ori_filename,a.id]} %>
<% elsif params[:id] == "ori" %>
<%= f.input :database_1_id, collection: AdOriTbl.all.order(otb_filename: :asc).collect{ |a| [a.otb_filename,a.id]} %>
<% elsif params[:id] == "mod" %>
<%= f.input :database_1_id, collection: AdQryMod.all.order(qry_mod_text: :asc).collect{ |a| [a.qry_mod_text,a.id]} %>
<% end %>
<% end %>
<% end %>
And now the file containing the target field.
# _fields_1.html.erb
<%= simple_form_for "audit_function" do |f| %>
<% if params[:id] %>
<% if params[:id].gsub(/_{1}\d{1,}\z/, "") == " mod " %>
<%= f.input :field_1_id, collection: AdQryFld.where(ad_qry_mod_id: params[:id].gsub(/\A\w{1,}_{1}/, "").to_i).order(order_id: :asc).collect{ |f| [f.qry_field_text,f.id]} %>
<% else %>
<%= f.input :field_1_id, collection: AdOriFld.where(ad_ori_tbl_id: params[:id].gsub(/\A\w{1,}_{1}/, "").to_i).order(id: :asc).collect{ |f| [f.otb_colhdg,f.id]} %>
<% end %>
<% end %>
<% end %>
The controller then contains all the actions triggered in the javascripts:
# audit_function_conroller.rb
def new
authorize! :new, :audit_functions
#audit_function = AuditFunction.new
#functions = [[I18n.t("text sum"),"sum"],[I18n.t("text quantity"),"quantity"],[I18n.t("text largest_value"),"largest_value"],[I18n.t("text smallest_value"),"smallest_value"]]
#databases = [[I18n.t("text original_database"),"imp"],[I18n.t("text archive_database"),"ori"],[I18n.t("text query_database"),"mod"]]
end
def update_database_1_id_select
if params[:id] == "mod"
type = "mod"
elsif params[:id] == "ori"
type = "ori"
elsif params[:id] == "imp"
type = "imp"
end
render partial: "databases_1", id: type
end
def update_field_1_id_select
type = params[:id]
render partial: "fields_1", id: type
end
Now, as messy as all of this looks, the good thing is that it gets the job done. And to clarify my MVC, these are the relations:
AdOriTbl has_many AdOriFlds
AdOriFld belongs_to AdOriTbl
AdQryMod has_many AdQryFlds
AdQryFld belongs_to AdQryMod
I hope the names don't bother you too much when reading this.
Now lets get back to the problem:
As I said this code works for creating a new object and everything is selected fine. But when I try to edit an object only the field with the database type (database_1 and database_2) are filled. The select boxes for the ID's of the databases are not rendered, while the boxes for the fields are. But all four ID fields are empty.
Now I already tried to fill the boxes by hand with a jQuery that basically looks similar to the ones I already have, but instead of getting triggered onChange, I trigger it when my audit_function has a database_id and render the select box and fill it with the value according value of database_id. This works as well.
The problem is that I can't do this with the field_id, because in the partial of database_1_id where the jQuery for the fields get triggered, I don't have the #audit_function object at hand and also it seems to interfere with the other javascripts.
Besides that I'd also like to think that there is a better way to do this, then my way. But I already tried other tutorials and ways and they either don't work when you don't have your straight-forward Country-State-City relationships or they don't work when editing.
So, any help would be really appreciated. Thanks!
I took the following tutorial as template to rewrite my cascading dropdown:
http://homeonrails.blogspot.de/2012/01/rails-31-linked-dropdown-cascading.html
So, now I throw all the different models into one array and filter it by appending names to the class, to differentiate not only by ID, but also by name. Also the jQuery Plugin chainedTo makes the code much more readable.
So, the controller looks now like this:
#types_for_dropdown = [[I18n.t("text archive_database"),"ori"],[I18n.t("text query_database"),"mod"]]
#tables_for_dropdown = []
#ad_qry_mods = AdQryMod.all
#ad_qry_mods.each do |i|
#tables_for_dropdown = #tables_for_dropdown << [i.qry_mod_text,"mod#{i.id}",{:class => "mod"}]
end
#ad_ori_tbls = AdOriTbl.all
#ad_ori_tbls.each do |i|
#tables_for_dropdown = #tables_for_dropdown << [i.otb_filename,"ori#{i.id}",{:class => "ori"}]
end
#fields_for_dropdown = []
#ad_qry_flds = AdQryFld.all
#ad_qry_flds.each do |i|
#fields_for_dropdown = #fields_for_dropdown << [i.qry_fieldname,i.id,{:class => "mod#{i.ad_qry_mod_id}"}]
end
#ad_ori_flds = AdOriFld.all
#ad_ori_flds.each do |i|
#fields_for_dropdown = #fields_for_dropdown << [i.otb_fieldname,i.id,{:class => "ori#{i.ad_ori_tbl_id}"}]
end
And the form looks like this:
<%= content_for :head do %>
<script>
$(document).ready(function(){
$('select#audit_function_database_1_id').chainedTo('select#audit_function_database_1');
$('select#audit_function_field_1_id').chainedTo('select#audit_function_database_1_id');
$('select#audit_function_database_2_id').chainedTo('select#audit_function_database_2');
$('select#audit_function_field_2_id').chainedTo('select#audit_function_database_2_id');
});
</script>
<% end %>
<div class="grid-6-12">
<%= f.input :database_1, label: I18n.t("field_label audit_function database_1"), hint: I18n.t("field_hint audit_function database_1"), as: :select, collection: #types_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_2, label: I18n.t("field_label audit_function database_2"), hint: I18n.t("field_hint audit_function database_2"), as: :select, collection: #types_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_1_id, label: I18n.t("field_label audit_function database_1_id"), hint: I18n.t("field_hint audit_function database_1_id"), as: :select, collection: #tables_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_2_id, label: I18n.t("field_label audit_function database_2_id"), hint: I18n.t("field_hint audit_function database_2_id"), as: :select, collection: #tables_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :field_1_id, label: I18n.t("field_label audit_function field_1_id"), hint: I18n.t("field_hint audit_function field_1_id"), as: :select, collection: #fields_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :field_2_id, label: I18n.t("field_label audit_function field_2_id"), hint: I18n.t("field_hint audit_function field_2_id"), as: :select, collection: #fields_for_dropdown, include_blank: true %>
</div>
This is really a nice solution and I can recommend it to everyone!