Trying to pass data from a view to controller using Javascript. How do I do this ? Specifically the information I wish to access in the controller is what option/s have been selected in a variable number (one to many) of selections on the screen.
I have a ROR application I am developing and on the "Companies - Drill Interests" screen I wish to use java/coffeescript to send data and invoke controller action. In the controller I can't get access to all the data I need to respond. That is I can' determine what "Saved Assumption" the user has selected.
From the Companies controller building array (should I be doing this or using another method) of saved assumptions.
def companies_drill_interests
# intial display use first (if present) user drill evaluations
#result_list = Array.new
#company_listings.each do |cl|
#drill_interests.each do |di|
target_share_price = 0
result = Hash.new
result["cl_display_name"] = cl.display_name
result["di"] = di.drill.name
result["target_share_price"] = 0
# if saved assumptions grab first assumption and then first target_share_price
#matched_evaluation_assumption =
EvaluationAssumption.matched_eval_assum(#current_user.id, di.drill_id)
...
# code that builds result ...
end
end
#result_list << result
end
end
end
from the screen partial views/companies/_companies_drill_interests
<%= simple_form_for #company,
html: { class: 'infogroup',
id: "x_company_drill_interests"} do |f| %>
<div class="infogroup-header">Drill Interests</div>
<div class="infogroup-body">
<table border="0" cellpadding="0" cellspacing="0" class="info">
<th class="very_large_column lalign">Drill Name</th>
...
<% if #drill_interests.present? %>
<% index = 0 %>
<% #drill_interests.each do |drill_interest| %>
<%= fields_for "drill_interest[]", drill_interest do |di| %>
<tr>
<td><%= drill_interest.drill.name %></td>
<td class="ralign"><%= drill_interest.equity_percentage %></td>
<% array_name = "evaluation_assumption" + index.to_s %>
<td id="x_user_eval_assum" class='lalign large_column' data-targets="<%= #probability_json %>">
<td> <%= select("mea_user_save_name", "id",
#assumptions[array_name].collect {|r| [ r["mea_user_save_name"], r["id"] ] },
{ :include_blank => false }) %> </td>
<% index += 1 %>
</tr>
<% end %>
...
If the user changes the "Saved Asumptions" selection this is detected in jave/coffeescript. From app/assets/javascript/companies.js.coffee
...
$('#x_company_drill_interests').change((event) ->
company_id = $('.form.companies_drill_interests').attr('data-companyid')
event.preventDefault()
calculateResult company_id
)
calculateResult = (company_id)->
data = $('#x_company_drill_interests').serialize()
$.ajax
url:"/companies/#{company_id}/projection.json",
type:"post"
...
Display statement in Companies Controller for when the action I can't get to work is performed.
class CompaniesController < ApplicationController
...
def projection
puts "================================="
puts "params = " + params.to_s
puts "================================="
...
In the logs output from this statement
params = {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"rFx8TBWnECUCxFiEBQ+0lTmkvhUKEJrUx/SlEQNPEP8=", "mea_user_save_name"=>{"id"=>""}, "action"=>"projection", "controller"=>"companies", "id"=>"18", "format"=>"json"}. The arrays are not present.
Overview of relationships between models.
Company has 0 to many drill_Interests. Each Drill_interest has 0 to many Evaluation_Assumptions (and using Evaluation_Assumptions I wish to display User_Evaluation_Results).
If you wish to see above you can visit the application as per instructions below.
1- go to http://quiet-fortress-3338.herokuapp.com/users/login
2- login with userid = pmlc and password = gmfive99
3- select companies from menu top RHS
4- select ADO
5- Select screen "Companies Drill Interests"
You will see ADO has an interest in both "Temp-01" and "ZZZ-Unlimited" with a number of saved assumptions for both
You are using fields_for, so change:
<td> <%= select("mea_user_save_name", "id",
#assumptions[array_name].collect {|r| [ r["mea_user_save_name"], r["id"] ] },
{ :include_blank => false }) %> </td>
to
<td> <%= di.select("mea_user_save_name", "id",
#assumptions[array_name].collect {|r| [ r["mea_user_save_name"], r["id"] ] },
{ :include_blank => false }) %> </td>
Try to use select_tag instead of select
select_tag statement
select_tag "whatever_name", options_from_collection_for_select(#assumptions[array_name].collect {|r| [ r["mea_user_save_name"], r["id"] ] }, "id", "mea_user_save_name"), include_blank: true
To send and array to backend using fields the fields must be named
<input name="myfieldarray[]">
In this way form.serialize() sends an array for myfieldarray.
check this question
How to pass an array from view to controller in Ruby on Rails
try this.
select_tag "my_array_param[]", options_from_collection_for_select(#assumptions[array_name].collect {|r| [ r["mea_user_save_name"], r["id"] ] }, "id", "mea_user_save_name"), include_blank: true
Related
I created a def sortable () in the /helpers folder in Ruby on Rails. I have a custom link_to aka <%= sortable , "name" , "Track" %> I would like to use in the <th> of my table but I cannot get it to wrap the whole tag.
I have tried passing in an jQuery .on("click")passing the <%= sortable "name" inside the <th> as an href and data-link.
<thead>
<tr class="tr-header">
**THIS*** <th class='track'> <%= sortable "name", "Track" %> </th>
<th class='delete'>DELETE TRACK</th>
</tr>
</thead>
The helper method
module TracksHelper
def sortable(column_name, title = nil)
title ||= column_name.titleize
direction = column_name == params[:sort] && params[:direction] == "asc" ? "desc" : "asc"
link_to title, { :sort => column_name, :direction => direction }, {:class => "fas-fa-sort"}
end
end
The controller
format.html {
pdog = params[:sort] == nil ? "" : params[:sort] + " " + params[:direction]
if (#current_user.admin != true)
# only for my tracks, unless we are admin
#tracks = Track.where(:user_id =>
#current_user.id).order(pdog).joins(:user)
else
# /index?approved=false
action = params['approved']
if action == 'false'
# test it in rails c for quicker trial and error
#tracks = Track.where(approved: false).joins(:user).order(pdog)
else
#tracks = Track.joins(:user).order(pdog)
end
end
}
I just want the whole <th> to use the <%= sortable, "name, "Track" %> that I created and I would like to know what is best practice.
Thanks in advance.
I was able to use raw() at first then switched to using a partial.
<%= render partial: "track_th", locals: {column_name: "name", title: "Track"} %>
then created another view.html.erb and passed in the helper method and html
<% title ||= column_name.titleize %>
<% direction = column_name == params[:sort] && params[:direction] == "asc" ? "desc" : "asc" %>
<th>
<span class="trackTable_th_span">
<%= link_to "?sort="+column_name+"&direction="+direction do %>
<%= title %><i class="fas fa-sort"></i>
<% end %>
</span>
</th>
I also used the same partial in a different view so I had to change the url as follows
<table id="myAccountTable">
<thead>
<tr class="tr-header">
<%= render partial: "/tracks/track_th", locals: {column_name: "name", title: "TRACK "} %>
<th class='delete'>DELETE TRACK</th>
</tr>
</thead>
I got help from someone fyi but I thought I would share the answer if anyone gets stuck trying to make <th> clickable in Rails
I am using filterrific gem to add filters in my app. I have parents table and children table. On the children_list page which displays list of all the children with their firstname and their parent's firstname. The issue I am facing is in the search query I want to add the parent.firstname search as well for filterrific. I tried adding a join as below:-
num_or_conds = 2
joins(child: :parent).where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?) "
But this didnt do the job. Any idea how this can be achieved.
parent.rb
has_many :children
child.rb
belongs_to :parent
filterrific(
available_filters: [
:search_query,
:with_clinic_date
]
)
scope :search_query, lambda { |query|
return nil if query.blank?
terms = query.downcase.split(/\s+/)
terms = terms.map { |e|
(e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
num_or_conds = 2
where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?)"
}.join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
)
}
scope :with_clinic_date, lambda { |ref_date|
where('children.clinic_date = ?', ref_date)
}
end
_children.html.erb
<h1>Children</h1>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Parent First Name</th>
<th>Child firstname</th>
</tr>
</thead>
<tbody>
<% #children.each do |child| %>
<tr>
<td><%=child.parent.firstname %></td>
<td><%=child.firstname %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
children-list.html.erb
<%= form_for_filterrific #filterrific do |f| %>
<div class="row">
<div class="col-sm-3">
Search
<%= f.text_field(
:search_query,
class: 'filterrific-periodically-observed form-control'
) %>
</div>
<div class="col-sm-3">
Request Date
<%= f.date_field(:with_clinic_date, class: 'js-datepicker form-control') %>
</div>
<div class="col-sm-3">
<br>
<%= link_to(
'Reset filters',
reset_filterrific_url,
) %>
</div>
</div>
<%= render_filterrific_spinner %>
<% end %>
<%= render( partial: 'children/children_list') %>
children.js.erb
<% js = escape_javascript(
render(partial: 'children/children_list')
) %>
$("#filterrific_results").html("<%= js %>");
AFAIK, you can't filter two separate classes on the same page. It will use the last defined filterrific instance. When I ran into this problem, I used remote forms with custom action/routes
# routes.rb
resources :parent do
get :filter_parents
resources: children do
get :filter_children
end
end
And then the controllers..
# parents_controller.rb
def index
parents_filter # this would be a helper method running your filter queries
end
def filter_parents
parents_filter # this would be a helper method running your filter queries
end
The children's controller would look similar, just different named helper method/custom action.
And then use a partial for the table. Target the table's container, and use a filter_parents.js.erb and filter_childrens.js.erb file
$('#parents-table').html('<%= escape_javascript render 'path/to/partial'%>')
// same in childrens.js.erb, just target the appropriate table
I work on a project with Ruby on rails. I currently have some issues with my index page on which I use Datatables to display my data.
I use the server-side option to display my data since it's a very large database. I added a selector to allow the user to select a project whose vulnerabilities he wants to see. I managed to get the project in my controller and I passed it in an instance variable because I need it in my view. However, the variable isn't reloaded with the ajax call.
How can I reload the instance variables in my view ? I don't need only the project but also other variables such as the displayed variables to make graphs depending on the criticity...
Maybe I'm doing this the wrong way. Could you help me ? Below is my code.
View :
<div class="col-md-8 col-xs-8" style="display: inline-block">
<div class="x_panel">
<h4>Filtres</h4>
<div class="x_content">
<div class="col-md-6 col-xs-6" style="display: inline-block">
<label>Filter by projet : </label>
<%= select_tag "datatable_project", options_from_collection_for_select(#user.projects, :id, :name), include_blank: "Tous", onchange: "selectProject(this.value)" %>
</div>
</div>
</div>
</div>
<div class="x_panel">
<table id="datatable-history-external" class="table responsive-utilities mcs-datatable-history-external" width="100%">
<thead>
<tr class="headings">
<th class="column-title all" style="width:150px">CVE</th>
<th class="column-title all">Base score</th>
<% if not #selected_project.nil? and #selected_project.level == 2 %>
<th class="column-title all">Environmental score</th>
<% else %>
<th class="column-title never"></th>
<% end %>
<th class="column-title none">Description</th>
</tr>
</thead>
</table>
</div>
I want to display an new column if the level of the selected project is 2. I tried to change the class from the javascript but it didn't work since I use responsive to display a childRow.
Controller :
def pagination
# Recuperation of the DataTable parameters
draw = params[:draw]
longueur = params[:length]
start = params[:start]
# Call method from model to get validated vulnerabilities
vulnerability_ids = []
#get project selection from the user
selected_project_id = get_selection
if not selected_project_id.blank?
#selected_project = Project.find(selected_project_id)
vulnerability_ids = #selected_project.validated_vulnerabilities.pluck(:id)
else
#user.projects.each {|project| vulnerability_ids += project.validated_vulnerabilities.pluck(:id)}
end
vulnerability_ids = vulnerability_ids.uniq
#vulnerabilities = Vulnerability.where(id: vulnerability_ids)
result = []
result = #vulnerabilities.offset(start.to_i).limit(longueur.to_i)
recordsTotal = #vulnerabilities.length
# creation of the json that we want to return and display
result_json = create_datatable_json(result, draw, recordsTotal)
render :json =>result_json.to_json
end
Controller Helper :
def get_selections
parameters = request.query_parameters
selected_project = parameters["project"]
return selected_project
end
def create_datatable_json(result, draw, recordsTotal)
vulns = []
result.each do |vul|
cves = []
#if there is a selected project and it is of level 2 we want to display a column with the max environmental notation
if #selected_project.nil? or not #selected_project.analysis_level == 2
max_environmental_score = "NC"
else
max_environmental_notation = EnvironmentalNotation.get_max_environmental_notation(vul, #selected_project).environmental_score
end
if vul.notation
vuln = [:id => vul.id, :cve => first_cves, :base_score => vul.notation.base_score.to_s, :description => vul.description, :environmental_score => max_environmental_score.to_s]
else
vuln = [:id => vul.id, :cve => first_cves, :base_score => "NC", :description => vul.description, :environmental_score => max_environmental_score.to_s]
end
vulns += vuln
end
result_json = {
:draw => draw,
:recordsTotal => recordsTotal,
:recordsFiltered => recordsTotal,
:data => vulns
}
return result_json
end
Javascript :
// Select project to filter the vulnerabilities to display in table
function selectProject(value) {
project = value;
Turbolinks.visit(window.location);
}
$(document).on("turbolinks:load", function() {
$('.mcs-datatable-history-external').each(function() {
if ($.fn.dataTable.isDataTable($(this))){
$(this).destroy();
}
var url = "vulnerabilities/pagination;
if (project != null) {
url = url+"/?project="+project;
$('#datatable_project').val(project);
}
add_in_array(
$(this).DataTable({
processing: true,
serverSide: true,
stateSave: true,
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.childRowImmediate,
type: '',
target: 3
}
},
ajax: {
type: "POST",
format: "js",
url: url
},
columns: [
{ data: "cve", targets:0},
{ data: "base_score", targets:1, orderable: true, searchable: true},
{ data: "environmental_score", targets:2, orderable: true, searchable: false},
{ data: "description", className: "no-border-top", targets:3, orderable: false, searchable: true},
],
searching: true,
}));
})
}
I need to get #selected_project and #vulnerabilities in my view but they are nil.
I don't know if I'm clear enough. I've put a lot of code here. Don't hesitate to ask for some explanations if needed.
first make sure that the changes are saved to data base later if the instance is not reloaded then you can use
#instance_variable.reload
To reload the instance
You can use it whenever you need to display/use the updated data of instance. Say there is an instance #user and you have updated the details of user like #user.email in the db and later you need to display the email of user using that instance like #user.email. In such case the instance doesnt get reloaded and it will display the previous value.
So if you use #user.reload then rails will fetch the details of that instance from DB. so that there will be less scope for error
I am trying to implement some nested form elements that have values based on a select box value in the main form. As it stands right now when I make the selection in the main form it changes the values displayed in all currently displayed nested form, but when I click the button to add a new nested form element, the new form elements display values that are not based on the primary select. What I need is for any time the button is clicked to add a new nested form, the values in that form should be based on the select box in the main form.
Here are the steps and what is happening:
Here are the steps and the desired results:
Here is what my partial looks like. This is what is displayed when the "new" button is clicked:
<tr class="details_row nested-fields">
<td><%= f.select :area_id, options_for_select(#areas.collect {|c| [ c.area_name, c.id ] }), {include_blank: true}, {:class => 'form-control area_select'} %></td>
<td><%= f.select :product_id, options_for_select(#products.collect {|p| [ p.product_number, p.id ] }), {include_blank: true}, {:class => 'form-control product_select'} %></td>
<td><%= f.number_field :quantity, class: 'form-control', "min" => 1 %></td>
<td><%= f.select :accessory_id, options_for_select(#accessories.collect {|p| [ p.product_number, p.id ] }), {include_blank: true}, {:class => 'form-control accessory_select'} %></td>
<td><%= f.text_field :notes, class: 'form-control' %></td>
<td><%= link_to_remove_association '<i class="fa fa-trash"></i>'.html_safe, f %></td>
</tr>
All of this action is when I'm creating a new record, here is the code from my controller for the new method:
def new
if current_user
#estimate = Estimate.new
#estimate.estimate_details.build
#default_user = current_user.id
#product_type = 3
#areas = Area.where("product_type_id = ?", #product_type)
#products = Product.select("product_number, id").where("product_type_id = ? AND active = 't' ", #product_type)
#accessories = Product.select("product_number, id").where("product_type_id = ? AND active = 't' AND accessory = 't'", #product_type)
else
redirect_to root_path, notice: 'You are not logged in.'
end
end
This is the method from the controller (the same controller as new above) that updates the select boxes:
def update_select
#product_type = params[:product_type_id]
#areas = Area.where("product_type_id = ?", params[:product_type_id])
#products = Product.where("product_type_id = ? AND active = 't'", params[:product_type_id])
#accessories = Product.where("product_type_id = ? AND active = 't' AND accessory = 't'", params[:product_type_id])
respond_to do |format|
format.js
end
end
I was thinking that #product_type would be set to the default in the "new" method of the controller. When the update_select method is run, it should update the #product_type and this would be used when the new elements were created...but that didn't work.
Update
Here is my update_select.js. This does update the three select boxes in the nested form, but I have to add a dynamic form and then make a selection in the main form select box in order for the fields to be correct for the newly added form details.
$(".area_select").empty().append("<%= escape_javascript(render(partial: "select_boxes/area", collection: #areas)) %>")
$(".product_select").empty().append("<%= escape_javascript(render(partial: "select_boxes/product", collection: #products)) %>")
$(".accessory_select").empty().append("<%= escape_javascript(render(partial: "select_boxes/accessory", collection: #accessories)) %>")
Here are the partials referenced by the above js:
Accessory:
<option value="<%= accessory.id %>"><%= accessory.product_number %></option>
Product:
<option value="<%= product.id %>"><%= product.product_number %></option>
Area:
<option value="<%= area.id %>"><%= area.area_name.titleize %></option>
And just for good measure here is the script that triggers the update_select
$ ->
$(document).on 'change', '#product_type_select', (evt) ->
$.ajax
url:'/estimates/new/update_select',
type: 'GET',
dataType: 'script',
data: {
product_type_id: $("#product_type_select option:selected").val()
}
error: (jqXHR, textStatus, errorThrown) ->
console.log("AJAX Error: #{textStatus} #{errorThrown}")
success: (data, textStatus, jqXHR) ->
console.log("Dynamic area select OK!")
Here's my controller
class ActivitiesController < ApplicationController
def exercises
if current_user.userprofile.present? #chef whether there is a userprofile object
#weeknum = current_user.userprofile.week
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
end #end check userprofile
end
def updatexercises
respond_to do | format |
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
#dayly_activity.update_attributes(params[:#dayly_activity])
#dayly_activity.save
format.html { render action: "exercises" }
end
end
end
And my template
<h1>WEEKLY EXERCICES</h1>
Day : <%= #dayly_activity.day %>
<%= form_for(#dayly_activity, :url => { :action => "updatexercises" }) do | f | %>
<table>
<tr>
<td>Jogging:</td>
<td>
<% list = (0..20).to_a %>
<%= f.select :jog, list %>
x 0.1 km
</td>
</tr>
<tr>
<td>Bicycling:</td>
<td>
<% list = (0..10).to_a %>
<%= f.select :bicycl, list %>
km
</td>
</tr>
<tr>
<td>Push ups:</td>
<td>
<% list = (0..20).to_a %>
<%= f.select :pushups, list %>
x 10 times
</td>
</tr>
<tr>
<td colspan = "2"><%= f.submit %></td>
</tr>
</table>
<% end %>
When I click the button, the Daily+activity object is not being saved. Am I missing some thing
EDIT
I've tried to hard code this way and it saving to the database.
#dayly_activity.jog = 17
#dayly_activity.pushups = 13
#dayly_activity.save
Obviously, the problem must be with the update_attributes
You need to use params[:dayly_activity] (drop the # sign).
Also, I would put these two lines :
#dayly_activity = Activity.where(:week => 1, :day => 'Monday').first
#dayly_activity.update_attributes(params[:dayly_activity])
Outside of your respond_to block (put them on top of it).
You can also drop the #dayly_activity.save, update_attributes do it automatically and will returns true/false if it works/fails.
You have error in [:#dayly_activity]
And in that code
#dayly_activity.update_attributes(params[:#dayly_activity])
#dayly_activity.save
save is useless. update_attributes saving the record.
It better to check result of update_attributes. So you can catch validation errors.
For example
if #dayly_activity.update_attributes(params[:dayly_activity])
redirect_to dayli_activity_path, :notice => "Updated"
else
render :edit
end