Re-directing path based on params passed in views - ruby-on-rails

I have the following two buttons in my index.html.haml:
= button_to t('payer_contracts.new_global_payer_contract'), new_payer_contract_path, {:class => 'btn pull-left', :method => 'get'}
= link_to t('payer_contracts.new_bpci_payer_contract'), new_payer_contract_path
As you can see they both go to new_payer_contract_path. How can I make it so that if the first button is clicked, I can send a param such as new_payer_contract_path(new_global_payer_contract) ?
The problem is: in my new.html.haml, both of them are rendering 'global_form'. I want the first button to render global_form and the second button to render 'bpci_form'
Here is the new.html.haml:
- content_for(:title, t('payer_contracts.page_titles.new'))
- content_for :article do
.common-main-container
%h1= t('payer_contracts.new_payer_contract')
= render 'global_form'
In my payer_contracts_controller I have this so far:
def new
#payer_contract = PayerContract.new(
id: '',
contract_name: '',
contract_type: {
id: '',
code_key: '',
display: '',
code_group: ''
},
amount: '',
stoploss_amount: '',
stoploss_reimbursement_percentage: '',
begin_date: '',
end_date: '',
timely_filing_days: '',
payer: ''
)
end

With button_to, you can pass a params hash:
<%= button_to t('payer_contracts.new_global_payer_contract'), new_payer_contract_path, class: 'btn pull-left', method: :get, params: { x: "y" } %>
This creates a hidden_field inside the form that button_to creates, allowing you to pass params[:x] to your next action.
Update
As per your comments, you're getting the params[:x] variable in your controller.
You just have to use this in your ActiveRecord query call:
#view
-if params["x"] == "y"
= render "global_form"
-else
= render "bpci_form"

Related

how to process form_with using GET request as XHR

I'm working on a Rails 6 app, and want to update page view based on a dropdown value selected using XHR. Dropdown must use GET method coz I am calling index action.
I am using form_with which by default uses remote: true.
I am not using local: true.
I tried onchange: "Rails.fire(this.form, 'submit')" - this does send XHR request and receives a response but does not update view.
I tried onchange: "this.form.submit();" - this does a full page reload not utilizing XHR.
Code from app/views/users/index.html.erb
<%= form_with url: station_users_path(station_id: Current.user.home_station), method: :get do |form| %>
<%= form.select :user_status, options_for_select( { "Active users" => "unlocked", "Inactive users" => "locked"}, #user_status ), {}, { :onchange => "Rails.fire(this.form, 'submit')" } %>
<% end %>
Code from app/controllers/users_controller.rb
def index
#user_status = params[:user_status] || "unlocked"
#users = #station.users.send(#user_status) || []
#user_status == "unlocked" ? seperate_managers_from_users : #managers = []
end
In onchange just write one get_station_users() function. Inside that you can use ajax calling.
In forms
<%= form_with url: station_users_path(station_id: Current.user.home_station), id: “form_id”, method: :get do |form| %>
<%= form.select :user_status, options_for_select( { "Active users" => "unlocked", "Inactive users" => "locked"}, #user_status ), {}, { :onchange => "get_station_users()" } %>
<% end %>
Add Script
function get_station_users(){
$.ajax({
type: "GET",
url: "/station_users",
data: { $('#form_id').serialize(), },
dataType: 'script'
});
}
Your response will be as JS. So you can use index.js.erb

How can I pass params using link_to?

I want to pass a parameter using link_to. (Also I am trying to use Bootstrap tab)
ilban.html.erb
<%= link_to '일반공지', '#home', { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab', :where => 1 } %>
cpu_controller.rb
#where = params[:where]
This code doesn't get where as an parameter. How can I fix it?
I have not tested it, but it should pass the params that you want.
link_to "Search", searches_path(:where => 1, :when => "Today"), { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab' }
Controller:
#where = params[:where]
In Rails 5, try this syntax for link_to
link_to 'Show', view_path(:id => view.id), { 'data-toggle' => 'tab', 'aria-controls'=>'home', 'role'=>'tab' }
In the place of view path you can edit with your controller path and pass the valid id that you need to link.
Or, try this syntax also to pass params
<%= link_to "Add car", {:controller => "car", :action => "add_car", :car => car.id }%>
And add in your controller
#car = Car.find(params[:car])

How to add 2 different flags for button clicks so that can add extra stuff to html view in Rails?

I am having 2 button fields which are redirected to same html page,
= link_to url_for(params.merge(action: 'my_report', format: :html)), class: 'button on-dark right', data: { toggle: 'modal', placement: 'left' } do
= t('reports.pdf_export')
= link_to url_for(params.merge(action: 'show', format: :pdf)), class: 'button on-dark right' do
= t('reports.all_pdf_export')
In that html I want to add extra stuff when we click on all_pdf_export button, can we add this by name or any flag to be added?
Please help me.
controller method:
def customer_report
#x = params[:x]
#y = params[:y]
#details = Detail.by_account(current_account).active.includes(:company, :primary_contact)
respond_to do |format|
format.html{ render layout: "modal" }
end
end
Button view:
= link_to url_for(params.merge(action: 'my_report', format: :html)), class: 'button on-dark right', data: { toggle: 'modal', placement: 'left' } do
= t('reports.pdf_export')
= button_to t('reports.all_pdf_export'), url_for(params.merge(action: 'customer_report', format: :html)), class: 'button on-dark right', params: { x: "value", y: "value" }, data: { toggle: 'modal', placement: 'left' } do
common view for both the links:
<div>
<%= #account.name %> <br/>
<%= #account.description %><br/>
<% if #x? %>
<%= #account.details %>
<% end %>
</div>
You'll probably be best using button_to, which creates a small form, allowing you the luxury of passing params through it:
= button_to t('reports.all_pdf_export'), url_for(params.merge(action: 'show', format: :pdf)), class: 'button on-dark right', params: { x: "value", y: "value" }
(button_to) generates a form containing a single button that submits to the URL created by the set of options. This is the safest method to ensure links that cause changes to your data are not triggered by search bots or accelerators.
If using the above, you'll be able to access the parameters in your controller as follows:
#app/controllers/your_controller.rb
class YourController < ApplicationController
def show
#x = params[:x]
#y = params[:y]
end
end
Update
You must remember to evaluate against the variable you set:
<%= #account.name %> <br/>
<%= #account.description %><br/>
<%= #account.details if #x == "value" %>

Rails check_box_tag how to pass value when checked ajaxily

On my index page for my Task model, I want to show a checkbox for every row that corresponds to the boolean field "complete" in my Task database table.
Currently my code gets into the method "Complete", but it does not contain the value of the checkbox that the user just did (i.e. if they just checked the box, it does not pass true to my "Complete" method).
How can i pass the value that the user just performed - either checked or un checked?
/views/tasks/index.html.erb
<% #tasks.each_with_index do |task, i| %>
<tr>
<td><%= check_box_tag 'Complete', task.complete, task.complete, :data => {:remote => true, :url => url_for( :action => 'complete', :id => task.id, :complete => task.complete ), :method => :put}, :class => 'input-large' %></td>
</tr>
<% end %>
/controllers/tasks_controller#complete
# PUT /complete/1
def complete
#task = Task.find(params[:id])
p "inside complete"
p "complete = #{params[:complete]}"
#task.complete =
if #task.update_attributes(params[:task])
p "inside update"
render :text => "success"
else
p "inside error"
end
end
The suggestion from this issue in rails/jquery-ujs github repo worked for me: https://github.com/rails/jquery-ujs/issues/440#issuecomment-197029277
For you it would be:
<%= check_box_tag 'complete', '1', task.complete, {
onchange: "$(this).data('params', 'complete=' + this.checked)",
data: { url: url_for(action: 'complete', id: task.id,), remote: true, method: :patch },
} %>
If you are using jQuery, you can write a click event.
$('.input-large').click(function() {
var checked;
if ($(this).is(':checked')) {
checked = true;
} else {
checked = false;
}
$.ajax({
type: "POST",
url: "/tasks/complete",
data: { id: $(this).data('post-id'), checked: checked }
});
});
As of Rails 4, you should be able to ditch all the JS from the original answer. The code in your question should just work due to jQuery UJS magic.
It turns out that adding remote: true to an input causes jquery-ujs to make it ajax-y in all the nice ways. Thoughtbot's "A Tour of Rails jQuery UJS" briefly touches this (and many other good things available); the "Unobtrusive scripting support for jQuery" page in the jQuery UJS wiki does a thorough job on this as well.
check_box_tag 'complete', task.complete ? 'false' : 'true', task.complete, ...
:url => url_for( :action => 'complete', :id => task.id )
This way in your controller you can get params[:complete].
And you should implement complete.js.erb to rerender checkbox, so next click will send inverse value
Or you can implement js on click event
$('.input-large').on('click', function() {
$.ajax({
type: "PUT",
url: "/tasks/complete/" + $(this).data('post-id')
data: { complete: $(this).is(':checked') }
});
});
and don't forget to place data-post-id param to your checkbox

Locals not set when rendering multiple partials from the same controller

This bug has me perplexed.
I am displaying a Widget with the last 5 data points and a form for a new data_point. When I try to render both the form and the display partial it fails with a routing error. If I comment out either partial it works fine. So with only the form partial it works, or with only the display partial it works fine with the other.
Three relevant models/controllers: Widget, DataSet and DataPoint. DataPoints is STI so I have different partials to display the different types that match the class name.
When both render :partial => ... are uncommented it looks as if the data_point being passed to the second partial is the same as the data_point being passed to the first partial. It is all nil with only a data_set_id. I tried renaming the local from :data_point to :dp in case it was a name collision.
View, both partials and the routing error shown at the bottom.
Is there a limitation on passing :locals to partials when you are trying to render more than one partial in a view?
View: show.html.haml (the show action on the controller is empty)
- title "#{#widget.type.underscore.humanize} for #{#widget.data_set.name.to_s.downcase}"
.row
.span6
= render :partial => 'data_points/form', :locals => { :data_set => #widget.data_set, :data_point => #widget.data_set.data_points.build }
%br
- last_5 = #widget.data_set.data_points.last(5)
- if last_5.count > 0
%h3= "Last #{pluralize( last_5.count, 'Entry' )}"
- last_5.each do |dp|
%pre
= dp.inspect
= render :partial => "data_points/#{#widget.data_set.data_type.underscore}", :locals => { :data_set => #widget.data_set, :data_point => dp }
- else
%h3 No data yet!
= form_tag( push_widget_path #widget, :method => 'POST' ) do
= submit_tag( "Push Data", :class=>"btn btn-primary" )
= link_to "Edit your data", data_set_path( #widget.data_set ), :class=>'btn'
.span6
= image_tag "widgets/#{#widget.type.underscore}.png"
%p
Using the
%b= link_to #widget.data_set.name, #widget.data_set
data set.
= render :partial => "widgets/#{#widget[:type].underscore}", :locals => { :widget => #widget } rescue nil
%p
= link_to 'Edit', edit_widget_path(#widget), :class=>'btn'
Form Partial (data_points/_form.html.haml)
%pre
= data_set.inspect
%pre
= data_point.inspect
= form_for [data_set,data_point], :html=>{:class => 'well form-horizontal'} do |f|
-if data_point.errors.any?
#error_explanation
%h2= "#{pluralize(data_point.errors.count, "error")} prohibited this data_point from being saved:"
%ul
- data_point.errors.full_messages.each do |msg|
%li= msg
= render :partial => "data_points/#{data_set.data_type.underscore}_form", :locals => { :f => f, :data_point => data_point, :data_set => data_set }
= f.text_field :created_at, :type=>'datetime'
.form-actions
= f.submit 'Save'
Display Partial (data_points/_multi_value_data_point.html.haml)
.data-point{ :id=>"data-point-#{data_point.id}"}
%span.value
- data_point.data.map do |k,v|
- label = data_set.properties[:data_series][k][:name]
%span.key= "#{label}: "
= v
.meta
= data_point.created_at
%span.edit
= link_to 'Edit', edit_data_set_data_point_path( data_set, data_point )
%span.delete
= link_to 'Destroy', [data_set, data_point], :method => :delete, :data => {:confirm => 'Are you sure?'}
=# link_to 'Edit', '#', id: "edit-data-point-#{data_point.id}"
:javascript
$("#edit-data-point-#{data_point.id}").click( function(e) {
$("#data-point-#{data_point.id}").html( "#{escape_javascript( render :partial => "data_points/multi_value_data_point_form", :locals => { data_set: data_set, data_point: data_point } )}");
return false;
});
Routing Error
Routing Error
No route matches {:action=>"edit", :controller=>"data_points", :data_set_id=>#<MultiValueDataSet id: 4, ... properties removed ... type: "MultiValueDataSet">, :id=>#<DataPoint id: nil, data: {}, data_set_id: 4, created_at: nil, updated_at: nil>}
Try running rake routes for more information on available routes.
The problem stems from the fact that the form is building a new element that isn't saved, and last is returning that unsaved element.
Simple solution, replace .last(5) with .find( :all, order: 'id desc', limit: 5 )

Resources