How to update/pre-populate Rails form using a dropdown - ruby-on-rails

I am trying to create a form with dropdown where users can create a new object if something like "Create new" is selected, or they have the option of choosing from their previously created objects, which should prefill the form with the corresponding data.
At the moment I simply have a for each loop filling the dropdown list with the previously created objects which is outside the form, and a form that creates new objects.
How can I make this form dynamic so that when a previously selected object is selected, the form pre-fills and allows for editing?

You'd have to send out an AJAX GET request to a custom route and then have a controller action that responds to json format and returns a collection based on params passed in that GET request. Say, you are loading available car models based on a selected make:
routes:
get '/get_models/:make_id', to: 'car_makes#available_models'
controller action:
def available_models
#models = Model.where(id: ids)
respond_to do |format|
format.json { render json: #models }
end
end
AJAX request:
var fetchModels = function(makeId){
$.ajax({
method: 'GET',
url: '/get_models/' + makeId,
success: function(data) {
...
var target = $('select#car_models'); // field to which options are appended
$.each(data, function(id, model){
$(target).append(
$('<option>').text(model).attr('value', id) // populate options );
});
}
...
});
}
and then setting the AJAX request to fire on .change event in a parent select field:
$('select#car_makes').change(function(){
var makeId = $(this).val();
fetchModels(makeId);
});
There are a number of resources explaining other ways to achieve this:
https://gorails.com/episodes/jquery-ujs-and-ajax
http://railscasts.com/episodes/88-dynamic-select-menus-revised

So I ended up looping through all of the potential options for the select dropdown, and looping through the edit rails form with all the potential options, and using jQuery onchange to show / hide the correct html.
This doesn't feel like a very good solution to me, especially as it has to load the html of all the options every time.. but I don't know what else to do and it works.
If anyone has any ideas for a better solution, let me know :)

Related

Is their any way?I could get the value of dropdown to use in controller using onchange event handler in ruby on rails application

I want to call a method using onchange event handler when a user changes the value on a dropdown.Below is the code for my dropdown box.
<%= select_tag :name,options_for_select(#tests.map{|u| [u.name]}.uniq),:onchange => 'update_dropdown(:name)' %>
In the controller i want a method.which takes the value of selection in dropdown as paramater:
Below code searches database for the document with value of the parameter given from view.And return the document.What are the changes i have to make to get the selection in the controller as the dropdown values are changed!
def update_dropdown(name)
#drop = Test.where("name" => name)
end
How to get the selection value from view into the controller as parameter?
I has a mongoDatabase with documents(row) consisting key named:name.I has 4 unique values under key name.I want user to select the value using dropdown.As the user selected the dropdown.Without page refresh the documents consisting values selected with the key name should be displayed.
Ex:under key name.I has four values for 200 documents.named:
["value1","value2","value3","value4"].These values are the options
for dropdown menu.If user selected any of the values.The documents consisting value for key name should be displayed.
All you need to make ajax call on onchange event. Here is a link to a helpful answer
stackoverflow.com/a/7952315/4136098
How to get the selection value from view into the controller as parameter
Only way is to send the data through either an HTTP or Ajax (XML) request.
Because you've not explained your user story very well, I'll explain the overall schematics on how to get it to work...
Stateless
HTTP makes Rails applications stateless - meaning that each time you send interactions to it, it will have to rebuild the user environment each time (this is why sessions are so important to Rails).
This means that each time you want to invoke new actions / methods, you have to send a request to your server. The request can be sent over several protocols (HTTP, XML and Websockets) - each has the same pattern: Request > Logic > Output
Thus, if you want to send data to your controller, you'll have to either have a full page refresh (follow the above pattern), or send the data via ajax.
Ajax
In this case I'd recommend using ajax to send a request to your controller.
# View
<%= select_tag :name,options_for_select(#tests.map{|u| [u.name]}.uniq), id: "select" %>
#app/assets/javascripts/application.js
$(document).on("change", "#select", function(e) {
$.get("/controller/update_dropdown", {id: $(this).val() }, function(data) {
# Do something here
});
});
This will allow you to use the following:
#config/routes.rb
resources :controller do
get :update_dropdown, on: :collection #-> url.com/controller/update_dropdown
end
#app/controllers/controller_controller.rb
class ControllerController < ApplicationController
def update_dropdown
# params[:id] will be available
#test = Test.find params[:id]
render json: #test.to_json
end
end

Redirecting from Rails new form to edit if field exist already?

I have a requirement when creating a new Foo object and a unique field foo_id exist already, I have to redirect to the edit page for that foo_id.
I'm using jQuery autocomplete with the foo_id textbox already and was wondering what the best way to do this?
My initial thought is to return an extra isExist attribute in the JSON that gets returned to jQuery autocomplete and based onselecting a foo_id, I'll check the isExist attribute and redirect.
Is there a better way to do this? Also, if I need to do a redirect from JavaScript, should I generate the path from Rails?
Based on Vidya's answer and found results from other questions, this is what I did:
in Foo's controller added:
def checkFooExists
#foo = Foo.find_by_foo_id params[:foo_id]
if !#foo.nil?
flash[:notice] = 'You entered an existing Foo ID, so here is the edit page'
flash.keep(:notice)
render :js => "window.location = '" + edit_foo_path(#foo) + "'"
else
render :nothing => true, :status => 409
end
end
in routes change:
#resources :foos
resources :foos do
collection do
get 'checkFooExists'
end
end
in application.js, in the autocomplete event handler for select for textbox add one jQuery get line:
select: function(event, ui) {
$.get("/foos/checkFooExists", { foo_id: ui.item.foo_id });
$('#bar').val(ui.item.bar);
return false;
}
There are a lot of ways to do this, but an easy way would be to send an ajax GET request (on the change event for the autocomplete) with the id of the selected Foo instance to a controller endpoint. Do a lookup with the id. If an instance with the id exists, return a 200; otherwise, return a 404. So you would have success and error handlers respectively to handle those cases.
At this point, you can do many more things. Your REST endpoint could send the result of foo_path(foo) (remember you looked up foo) in the body of the 200 response. You could keep a list on the client side of all the different foo_path(:id)s corresponding to the choices in your autocomplete and pick the right one on success. Either way, you can then set document.location in your JavaScript to the correct path.
And probably a lot of other things others will point out I'm sure.

Rails don't reload session-data immediately after AJAX call but only on reloading whole page?

Basically, I have multiple-select box in the page. When the select box is changed, i want to put in session all id's being selected (one or more). The reason why i need something like that is following:
While creating new product user can create many variants of that product based on selected options(for example: Color and Size)(id's mentioned above).
So for example one product can have 2 variants(T-shirt in black color with size XL and green T-shirt with size L)
First of all i created POST route in products controller on which through AJAX i will send selected options:
resources :products do
collection do
post 'ajaxify_options'
end
end
Ajax code
$('#variant-options').change(function() {
var option_values = [];
$("#variant-options option:selected").each(function() {
option_values.push($(this).val());
});
$.ajax({
url: '/products/ajaxify_options',
type: 'POST',
data: ({'ids': option_values})
});
});
ajaxify_options action
def ajaxify_options (inside product controller)
set_option_values params[:ids]
head :ok, :content_type => 'text/html'
end
Here set_option_values is method in ApplicationController defined as:
def set_option_values option_values
session[:option_values] = [] if session[:option_values].nil?
session[:option_values] = option_values
end
with get method also (implemented as helper_method inside ApplicationController)
def get_option_values
return [] if session[:option_values].nil?
session[:option_values]
end
So now when user choose option (one or more) through get_option_values i can access to selected options from anywhere i need (partials for creating new product and variants).
Main-problem: When user select one or more options, through debugging i see that there is NO errors with ajax or server-side code everything is just fine and i can inspect values of selected options. But rails DO NOT reload session data immediately after AJAX call BUT only when i reload whole page.
Side-problem: Is everything fine with this code, i don't know why i think that I violate some Rails practices with populating session through ajax?
Similar question that i find is: Rails not reloading session on ajax post
I tried that solution but result is same.

Parent-Child form

How do I show a parent-child relationship on a single page in Rails? I don't need a form as I simply want to show the information (no edits or updates required). The parent is customer and the child is orders. I want to able to select a customer, display some customer information such as address, and list all orders placed in row format. Thanks.
It isn't entirely clear what you want here. I am assuming you want to have a list of customers, and when you click on one of them, other page is being populated with its details. If so, the nicest solution is to use Ajax event which will get the details from a server and place it in given div. Action in customers_controller would be sth like:
def details
#customer = Customer.find(params[:id])
render 'details', :layout => false # remember to add view 'details'
# and appropriate route in routes.
end
and javascript (jQuery) (note it is not perfect ajax call, it doesn;t handle multiple clicks and other problems, but shoud get you started)
$('.customer-row').click(function() {
customer_id = $(this).data('id');
$.ajax({
url: "/customers/" + customer_id + "/details",
type: "get",
success: function(details) {
$('#customer_details').html(details)
}
});
});
Then in your basic view you need to have div with id 'customer_details' somewhere and each of customer row should look like class="customer-row">.
In terms on how to access child objects inside details view it is as simple as:
<% #customer.orders.each do |order|>
# display order
<% end %>
Assuming you have your model associations set up properly..
In the controller,
#customer = Customer.find(params[:id])
#orders = #customer.orders.all
Then in the view, use the orders variable.

Where to store view parameters in an AJAX session?

In a non-AJAX web app, the URL would contain my view parameters (e.g. mysite?page=2&sort=name). In an AJAX app, where do I store the same info? In the Session object?
I'm assuming you want to know how to pass additional params with an AJAX call. This really depends on how you're formulating the AJAX call.
If you're using the built-in Rails helpers, you can pass additional params inside the url_for helper. For example, lets say that you have a products route and you want to AJAX load a list of all products. The link_to helper might look something like this (Rails 3.2)
link_to "All Products", products_path(:page => 2, :sort => "name"), :remote => true
If on the other hand you're using a JavaScript framework like jQuery, you can pass additional params using the data option. For example
$.ajax({
url: "/products",
data: {
page: 2,
sort: "name"
},
success: function(data) {
// handle success
},
failure: function(data) {
// handle failure
}
});
Storing this data (page, sort, etc.) can be done multiple ways also. The easiest way would be to store this data inside a JavaScript variable.
window.page = 2;
window.sort = "name";
Another solution is to store this information in the data attribute of a particular DOM element on the page. For example, if you have a <div id='products'> that contains a list of the paginated, sorted products, you could store the information like this (jQuery)
$("#products").data("page", 2);
$("#products").data("sort", "name");
Generally speaking, you don't structure you're requests differently for AJAX in Rails. You'll just add the :remote => true attribute to your link or form, then make the controller action respond_to js
respond_to do |format|
format.js
end
And then put your_action.js.erb in your views and write javascript that updates the dom in the appropriate way.

Resources