I am trying to render a partial upon change in the drop down list.
There is the onchange javascript function which directs to a link to display the corresponding form.
But here I am getting a #<ActionController::UnknownFormat: ActionController::UnknownFormat> error inside the get_template method in controller.
I suppose it is something to do with calling the link through javascript, as the request is processed as HTML.
Processing by XYZController#get_template as HTML
How to process it as JS ?
Here's the detailed code.
dropdown.html.erb
<div id="requests_dropdown">
Choose the type of request : <%= select_tag 'drop_request_id', options_for_select(#request_types.map{|x| [x[:name], x[:id]] } ) %>
</div>
Javascript
<script>
$('#drop_request_id').on('change', function() {
var request_type_id = $('#drop_request_id').val();
var href = 'get_template/' + request_type_id ;
window.location = href;
});
</script>
controller
def get_template
#request_type = [x,y,z]
respond_to do |format|
format.js
end
end
get_template.js.erb
$("#request_form_partial").html("<%= escape_javascript(render partial: 'request_form', locals: { request_type: #request_type } ) %>");
You need to call your method via ajax.
You are getting error because you are trying to GET the html format,whereas your method renders the js format response.
Please edit your code to following:
<script> $('#drop_request_id').on('change', function() {
var request_type_id = $('#drop_request_id').val();
var href = 'get_template.js/' + request_type_id ;
$.get(href);
});
</script>
Related
I have an AJAX call in my application.js which sends 3 pieces of data to my events_controller#check action:
//application.js
$(document).on('click', "#check-button", function(){
...
$.ajax({
url: '/events/check',
data: {checkList: checkList , selected_date: selectedDate , length: length },
}
);
});
my check action:
#events_controller.rb
def check
checkList = params[:checkList]
selected_date = params[:selected_date]
length = params[:length]
busy_array = Array.new #this needs to be rendered in the view
...
busy_array.push(user.id) #busy_array is a list of user ids from database
end
#routes.rb
resources :events do
get :check, on: :collection
end
The view:
<button id="check-button" type="button">Check</button>
<div class = "col-md-6" id="unavailable">
<h2>Unavailable on this day:</h2>
<ol id="unavailable-list">
<li>THIS LIST SHOULD BE POPULATED BY BUSY_ARRAY</li>
</ol>
</div>
Now I need to send back data from events_controller#check to the view, but I don't know how to send busy_array to be rendered in events\new.html.erb
Thanks for you help, I am a ruby/JS beginner
busy_array = Array.new #this needs to be rendered in the view
If that has to be available in the view, you need to define an #instance variable:
def check
checkList = params[:checkList]
selected_date = params[:selected_date]
length = params[:length]
#busy_array = Array.new
...
#busy_array.push(user.id) #busy_array is a list of user ids from database
end
Each time you call a controller#action, the data/variables within the action are bound by local scope.
Outputting data in the view requires the variable to be made available across the entire instance of the class (not just the action/function). Thus #busy_array.
Fix
#app/views/events/....
<%= button_to "Check", events_check_path %>
<div class = "col-md-6" id="unavailable">
<h2>Unavailable on this day:</h2>
<ol id="unavailable-list"> </ol>
</div>
#app/assets/javascripts/application.js
$(document).on('click', "#check-button", function(e){
...
$.get('/events/check', {checkList: checkList , selected_date: selectedDate , length: length});
});
#app/controllers/events_controller.rb
class EventsController < ApplicationController
def check
#busy_array = User.joins(:event).where(event: { ... }).pluck(:id) #-> return user ids where event.x = y
respond_to do |format|
format.js #-> invokes app/views/events/check.js.erb
format.html #-> invoked when HTML request sent
end
end
end
#app/views/events/check.js.erb
<% #busy_array.each do |id| %>
$("ol#unavailable-list").append("<%=j id %>")
<% end %>
I don't know how to send busy_array to be rendered in events\new.html.erb
The variable will be available in new if it's an #instance var:
#app/views/events/new.html.erb
<%= #busy_array %>
The view is part of the instance of your EventsController class, but outside the scope of the check method. When you send a request to Rails, it uses an instance of the Controller to compile a set of HTML to return to your browser.
For example, you could sum up the EventsController flow as such:
Request > Routing > EventsController.new(request).action > Returned HTML
If you set EventsController.new(request) manually, you'd have the following:
#event = EventsController.new request
#event.check #-> "busy_array" locally scoped to this function
#event.response #-> outputs view code.... #busy_array needs to be instance var
You'll understand better if you read up about MVC:
For a real AJAX request in Ruby on Rails, you need to send response from check action in JS format.
events_controller.rb
def check
checkList = params[:checkList]
selected_date = params[:selected_date]
length = params[:length]
#events = Event.where("checklist = ? and date = ?, checkList, selected_date).limit(length.to_i)
...
respond_to do |format|
format.js
end
end
Now, in your view, instead a check.html.erb, you will have check.js.erb. In this Javascript file, you can access to your # variables and render partials or wherever.
check.js.erb
$("#unavailable-list").append('<%= escape_javascript( render :partial => "events/event", :collection => #events ) %>');
_event.html.erb
<li><%= event.name %></li>
I change busy_array for events array because I don't know what's exactly busy_array but you can change it.
This is the flow for an AJAX request.
In my rails app I have a dropdown menu that a user can select an account to make a payment to:
//_payment.html.erb
<div class="field" id="payment-to-account">
<%= f.label 'Payment To:' %><br>
<%= f.collection_select :to_account_id, #liability_account_payment_list, :id, :account_details, {include_blank: 'Please Select'} %>
</div>
When the user selects a account I render a partial inside of this form based on their selection:
//_payment.html.erb
<%= form_for(#transaction,
as: :transaction,
url:
#transaction.id ? account_transaction_path(#account, #transaction) : account_transactions_path) do |f| %>
...
<% #f = f %>
<div id="to-account-form" style="display:none;"></div>
...
<script>
jQuery(function(){
$("#payment-to-account").change(function() {
var selected_item = $( "#payment-to-account option:selected" ).text();
var selected_item_index = $( "#payment-to-account option:selected" ).index();
//looks for account type in parentheses followed by space moneysign " $"
var regExp = /\(([^)]+)\)\s\$/;
var matches = regExp.exec(selected_item);
// array of account ids in order of list
var payment_account_ids = <%= raw #payment_list_ids %>;
switch (matches[1]) {
case 'Mortgage':
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
$('#to-account-form').slideDown(350);
break;
case 'PersonalLoan':
case 'CreditCard':
case 'StudentLoan':
case 'OtherLiability':
$('#to-account-form').html("<%= j render 'payment_to_all_other_liabilities', f: #f %>");
$('#to-account-form').slideDown(350);
break;
default:
$('#to-account-form').html("<br>" + "Contact support, an error has occurred");
$('#to-account-form').slideDown(350);
}
});
});
</script>
Right now it renders the correct partial based on the selection, but when that partial loads I need more information from the account model. I created a method called find_pay_to_account that take the input selected account id in the Accounts model that looks for the account based on the id.
When the user selects and account from the drop down, I'd like that method called on the partial that is loaded so I can show the user additional information about the account they are making a payment to before they submit the form. But I don't know how. I wanted to add something like this to my jQuery switch statement.
selected_account_id = payment_account_ids[selected_item_index-1]
#payment_to_account = Account.find_pay_to_account(selected_account_id)
Since rails preloads the partials in the background, making the following change to my partial render in the case statements still wont work:
From this
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
To this
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f, #payment_to_account: #payment_to_account %>");
I did some searching and found that with AJAX might be able to help:
Pragmatic Studio
Rails Cast
But i'm trying to access the model, not the controller and I'm trying to update a form partial. What is the correct way to do this?
Here are pics that show the user flow. An example of what I'm trying to update can be seen in the last pic. When the mortgage account is selected, it needs to show the minimum payment for the mortgage account. Right now it says zero because the partials rendering with all the information from BOA seed 0214.
If you want to access record information from your model inside of front-end javascript you will indeed want to setup a small api to query the database for that information. In ajax it would be something like this
function processDataFunction(data){
console.log(data)
}
$.ajax({
type: "GET",
dataType: "json",
url: "/some-path/:some_id",
success: processDataFunction(data){}
});
#config/routes.rb
Rails.application.routes.draw do
get "/some-path/:some_id", to: "some_controller#some_view", :defaults => { :format => :json }
end
#app/controllers/some_controller.rb
class SomeController < ApplicationController
def some_view
#some_records = SomeModel.find_by_id(params[:some_id])
respond_to do |format|
format.json { render json: #some_records }
end
end
end
To access the information in the rendered partial without making another controller action, I collected all data I might need in the original action. That way I could get the exact result I was looking for without changing my routes and doing ajax request.
To do this I added methods to the controller new action. You can see from my original question, all accounts I may need information for are in the variable that is in the dropdown menu:
#liability_account_payment_list
This is where the dropdown menu gets its information from
That variable is in the Transaction controller new action. So I created another variable storing an array on the line after the above variable:
#liability_accounts_payment_list_minimum_payments = #liability_account_payment_list.map {|account| account.minimum_payment.to_f + account.minimum_escrow_payment.to_f}
This new variable is an array of all the accounts minimum payments in the order they are listed in the dropdown menu the user will select from.
Then I changed the jQuery on the page to the following
//_payments.html.erb
<script>
jQuery(function(){
$("#payment-to-account").change(function() {
var selected_item = $( "#payment-to-account option:selected" ).text();
var selected_item_index = $( "#payment-to-account option:selected" ).index();
//looks for something in parentheses followed by space moneysign " $"
var regExp = /\(([^)]+)\)\s\$/;
var matches = regExp.exec(selected_item);
// array of minimum payments from accounts in list converted from ruby to js
var min_payments = <%= raw #liability_accounts_payment_list_minimum_payments %>;
// set the js variable to the appropriate minimum payment
var selected_account_min_payment = min_payments[selected_item_index-1];
switch (matches[1]) {
case 'Mortgage':
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
$('#to-account-form').slideDown(350);
break;
case 'PersonalLoan':
case 'CreditCard':
case 'StudentLoan':
case 'OtherLiability':
$('#to-account-form').html("<%= j render 'payment_to_all_other_liabilities', f: #f %>");
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
$('#to-account-form').slideDown(350);
break;
default:
$('#to-account-form').html("<br>" + "Contact support, an error has occurred");
$('#to-account-form').slideDown(350);
}
});
});
</script>
The lines that have min-payment-field-hidden are because setting two different divs with the same id does not work. One div is being used to set hidden_field, the other is showing the user what the value is.
//_payment.html.erb
<-- To make sure the appropriate minimum payment is submitted to controller -->
<%= f.hidden_field :amount, :id => "min-payment-field-hidden" %>
<div>
<%= f.label "Minimum Payment" %>
<div id="min-payment-field"></div>
</div>
If you look at my switch statement, you can see I set the above value with these lines:
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
Now the user can see the minimum payment for the specific account they choose from the dropdown.
Solved this:
I have a following situation:
I have Graph and Node model.
While on graph/show.html.erb I make an ajax post with an id of a Node:
var val = document.getElementById('nodeName').value;
if(val){
$.post("/nodes/this_node/", {id:val});
console.log(val);
}
How do I get that Node to render on the same page in, for example, ?
EDIT::
I have a custom POST action in node_controller :
def this_node
#node = Node.find(idd)
respond_to do |format|
format.js
end
end
I had to add app/views/nodes/this_node.js.erb with:
$("#node_div").html('<%= escape_javascript(render :partial => "node_content", :locals => { :node => #node}) %>');
and a partial in views/nodes/_node_content.html.erb
<%= #node.content %>
All works.
EDIT:
Actually fixed it (above code works)
I'm interested in using the jQuery UI autocomplete plugin in my Rails app. The number of possible values will be small, so I wanted to store them client-side. So I have my controller set up as follows:
def index
#tags = Tag.find(:all).map { |t| t.name }
end
And in my view:
var tags = <%= #tags %>
The problem is that this renders as:
var tags = ["tag1","tag2"];
Instead of:
var tags = ["tag1","tag2"]
What do I need to do differently in order to stop escaping those quotes inside my tag array?
What about:
var tags = <%=raw #tags %>;
EDIT:
in your controller
#tags = Tag.find(:all).map(&:name).to_json
in your view:
var tags = <%= #tags %>;
It's the same as what you presented but you're sure it's valid and sure (because escaped) json (+ the query is improved).
I'm still questioning about the XSS + raw...
I was able to solve this by changing my view code to:
<%= array_or_string_for_javascript(#tags) %>
The thing missing in your controller is html_safe - here is an example:
controller
#keys = #categories.map { |x| x.name }
#autocomplete_categories = #keys.to_json.html_safe
view:
<script type="text/javascript">
$(document).ready(function() {
var data = <%= #autocomplete_categories %>;
$("#auto").autocomplete( { source: data } );
});
</script>
I'm using the jQuery autocomplete plugin, and I want to customize this event:
select: function(event, ui) {
$('.topic_field').val(ui.item.topic.name);
return false;
Essentially, it triggers callbacks when an element from the dropdown list is selected. As of now, it only adds the selected element to the text field. I want both the field to be populated and for my application to send a POST request to the video update controller action, so that the user does not need to explicitly press the button. How can I do this?
UPDATE:
Here is the form in the show view of the video controller:
<%= form_for #video, :url => {:action => "update"}, :remote => true do |f| %>
<div class="field">
<%= f.text_field :topic_names, :class => "topic_field" %>
</div>
<%= f.submit "Add Topic" %>
<% end %>
Here is my jQuery code:
var url = $('.edit_video').attr('action');
var val = ui.item.topic.name;
$.post(url, {data:val});
This is in my routes.rb:
resources :videos
resources :video_votes
resources :users
resources :profiles
resources :genres
resources :topics
resources :topicables
resource :session
Here's my update action:
def update
#video = current_user.videos.find(params[:id])
respond_to do |format|
if #video.update_attributes(params[:video])
format.html { redirect_to(#video) }
format.js
else
format.html { render :action => "edit" }
end
end
end
Check out the jQuery.post documentation on how to post the data from your select box to the relevant controller action.
I'm not familiar with the autocomplete plugin, but I presume it follows an onChange event on your select box. When the user has made a selection, you should execute the following (untested):
var url = $('myForm').attr('action');
var val = $('mySelectBox').val();
$.post(url, {data:val})
In your controller, you could access this using:
params[:data]
which would return the value of your select box. You can then use this as normal in your controller code.
use the jquery ajax function to fetch the data from your action url ("/topics/list") or something
$.post('video/update',
data: {yourdata},
function(data) {
//callback function
}
);
in your video#update be sure to return something for your js request:
def update
blah
respond_to do |format|
format.js { return somethinghere }
end
end