Rails - Saving a new data from other module - ruby-on-rails

I have Client model and Contact model. On the Client page, I put "Add to Contact" button to save it on the contact model.
I have this code on my client page:
= form_for(#contact, remote: true, html: { class: 'form-horizontal ajax-form add-to-contact', style: 'margin-bottom: 0;', 'data-model-name' => 'contact'}) do |f|
= f.text_field :type, :value => 'clients'
= f.text_field :client_id, :value => client.id
= f.submit "Add to Contact", class: 'btn btn-success btn-submit-add-to-contact'
clients_controler.rb
def index
#contact = Contact.new(params[:client_id], params[:type])
end
contacts_controller.rb
def create
#contact = Contact.new(contact_params)
respond_to do |format|
if #contact.save
format.js {}
else
format.json { render json: #contact.errors, status: :unprocessable_entity }
end
end
end
And I have coffeesript code that when I submit it, it will save to contact model:
$(document).on "click", ".btn-submit-add-to-contact", ->
$(this).prop "disabled", true
$(this).val "Added to Contacts!"
$(".add-to-contact").submit()
But there's a problem on saving. All of my clients save, as in they're looping and automatically saving although I'm not submitting other client. Please help.

You should remove remote: true if you are adding you own Ajax functionality.
Also you should prevent the default click action or the browser will submit the form twice.
$(document).on "click", ".btn-submit-add-to-contact", ->(e)
$(this).prop "disabled", true
$(this).val "Added to Contacts!"
$(".add-to-contact").submit()
e.preventDefault()
If you are using jquery-ujs you should listen for the completed ajax call instead:
$(document).ready ->
$("form").on("ajax:success", (e, data, status, xhr) ->

I got this.
I've modified my JS:
$(document).on "click", ".btn-submit-add-to-contact", ->
$(this).prop "disabled", true
$(this).val "Added to Contacts!"
contact_form = $(this).closest('.add-to-contact-form').find('.ajax-form')
contact_form.submit()
return
And I put class before my form:
.add-to-contact-form
= form_for(#contact, remote: true, html: { class: 'form-horizontal ajax-form add-to-contact', style: 'margin-bottom: 0;', 'data-model-name' => 'contact'}) do |f|
= f.text_field :type, :value => 'clients'
= f.text_field :client_id, :value => client.id
= f.submit "Add to Contact", class: 'btn btn-success btn-submit-add-to-contact'
I use .closest and it works fine to me.
Thanks for helping me!

Related

Using js.erb in rails

In Rails 5 app with devise, I need to use a new.js.erb file to update select tag in my registrations view and controller. I cant seem to figure out why my new.js.erb file isn't working.
I've tried to use respond_to in controller as below,
registrations-controller.rb
def new
super
#cities = CS.get(:us,params[:state])
respond_to do |format|
format.js { render '/new.js.erb' }# layout: false }
format.html
end
end
new.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), :remote => true) do |f| %>
<div class="signup-input-container">
<div class="field">
<%= f.text_field :firstname, autofocus: true, autocomplete: "firstname", placeholder: "First name", class: "signup-input-container--input" %>
</div>
<div class="field">
<%= f.select :state, options_for_select(CS.states(:us).map { |code, name| [name, code] }),{:prompt => "State"}, {:class => "signup-input-container--input", :id => "state-picker"} %>
</div>
<div class="field">
<%= f.select :city, options_for_select([]),{}, {:class => "signup-input-container--input", :id => "city-picker"} %>
</div>
</div>
<% end %>
new.js.erb
var city = document.getElementById("city-picker");
while (city.firstChild) city.removeChild(city.firstChild);
var placeholder = document.createElement("option");
placeholder.text = "Choose a city";
placeholder.value = "";
city.appendChild(placeholder);
<% #cities.each do |c| %>
city.options[city.options.length] = new Option('<%= c %>');
<% end %>
main.js
var state = document.getElementById("state-picker");
state.addEventListener("change", function() {
$.ajax({
url: "/states?state=" + state.value,
type: "GET"
})
})
I'm expecting this to create select tag options with my array of cities in my controller. Does anyone know how to get this to work?
To solve this you should just setup a separate controller where you can fetch the data from asynchronously and alternatively there are also several free API's which can be used for geographical lookup such as Googles Geocoding API and Geonames.
To setup a separate controller you can do it by:
# /config/routes.rb
get '/states/:state_id/cities', to: 'cities#index'
# /app/controllers/cities_controller.rb
class CitiesController < ApplicationController
# GET
def index
#cities = CS.get(:us, params[:state_id])
respond_to do |f|
f.json { render json: #cities }
end
end
end
I would skip using a .js.erb template altogether and just return JSON data which you can use directly in your JS or with one of the many existing autocomplete solutions. .js.erb only makes sense for extensive HTML templating (like for example rendering an entire form) where you want to reuse your server side templates - it greatly increases the complexity and generally makes a mess of your javascript which is not worth it just to output a list of option tags.
// If you are using jQuery you might as well setup a delegated
// handler that works with turbolinks,
$(document).on('change', '#state-picker', function(){
$.getJSON("/states/" + $(this).value() + "/cities", function(data){
// using a fragment avoids updating the DOM for every iteration.
var $frag = $('<select>');
$.each(data, function(city){
$frag.append$('<option>' + data + '</option>');
});
$('#city-picker').empty()
.append($('frag').children('option'));
});
});

How to send email based on date time in Rails?

I am having a "send email" functionality in my application which sends email to the email addresses.
Later a new functionality is added where when the user checks on "Send email later" radio button, selects date and time and clicks on send email button so that the email is sent at particular time.
For this I added a field into database with column "send_reports_at", added to controller and required actions.
The date time is stored as : "2016-11-01 16:15".
How to add the condition of sending email based on the date time in my application(I am new to delayed job and all)?
Please help.
This is my view:
<%= f.input :additional_emails, :label => false, :input_html => {:id => 'sponge_contacts', :placeholder => 'Separate emails by comma', :class => 'deliver_page_email', :type => 'text', :rows => 2, :style=> 'width:300px; border-color:#ccc; font-size:13px; padding:10px 0 0 10px; width: 295px; height: 110px; resize: none;'} %>
<input type="radio" id="send_email_0" name="send_email" value="now" checked> Send email now<br>
<input type="radio" id="send_email_1" name="send_email" value="later"> Send email later<br>
<%= f.input :send_reports_at,:label => false, :input_html => {:placeholder => 'Click here to select date and times', :class => 'deliver_page_email', :type => 'text', :rows => 2} %>
<% content_for :javascript do %>
<script type="text/javascript">
$( function() {
$( "#report_send_reports_at" ).datepicker();
} );
$(document).ready(function() {
$("#report_send_reports_at").hide();
$("#send_email_0, #send_email_1").bind('change click',function(){
toggleResult();
});
});
function toggleResult(){
result = $("[name='send_email']:checked").val();
if(result == "later"){
$("#report_send_reports_at").show();
}else{
$("#report_send_reports_at").hide();
}
}
</script>
<% end %>
<% end %>
<%= link_to "Send Now", '#', :class => "pink_button _round_5", :id => 'send_now_button' %>
This is my controller method:
def send_report_email
send_to_agents = params.has_key?("send_to_agents") && params["send_to_agents"] == "true"
if #report.photos.empty?
Screenshot.delay.new(#user.id, #report.id, Rails.application.config.custom.indicator_screenshot_bucket)
else
Screenshot.delay.new(#user.id, #report.id, "photo_screenshots")
end
Screenshot.delay.new(#user.id, #report.id, Rails.application.config.custom.report_screenshot_bucket)
if #report.update_attributes(params[:report])
set_photo_position(false)
#report.save
if send_to_agents
#report.update_attribute(:duplicable, true)
#good_emails, #bad_emails, #unsubscribed_emails = #user.account.users.map(&:email), [], []
else
#good_emails, #bad_emails, #unsubscribed_emails = filter_emails(#report.additional_emails)
#user.delay.add_new_contacts(#good_emails)
end
#good_emails.each do |email|
send_to_agents == true ? ReportMailer.delay.additional_emails(email, #user, #report, "A new report is available: #{#report.title}") : ReportMailer.delay.additional_emails(email, #user, #report)
end
ReportMailer.delay.report_sent(#user, #report, #good_emails, #bad_emails, #unsubscribed_emails)
end
respond_to do |format|
format.json { render :json => { :success => true, :report_id => #report.id, :redirect => user_reports_url(current_user), :notice => 'Report was successfully sent!' } }
end
end
You could write a function (for instance a class method for ReportMailer) that sends all of the email whose scheduled time matches or is less than the current time, then set a cron job to use rails runner to run that function as often as necessary.

Using AJAX with two select boxes in Rails 4

I have a view containing two select boxes: company and employee. Both have a blank option and when a company is selected, it populates the employees based on the selected company. This works just fine. My issue is that when I submit a form that fails validation (as expected) and I select a company once more once the 'new' view renders again in extensions#create, my 'get' AJAX call has changed from /servers/1/extensions/get_company_employees (correct) to /servers/1/get_company_employees (incorrect) and is returning 404 Not found. Why is this happening and what should I do to remedy this? All relevant code is listed below
routes.config
resources :servers do
scope module: 'servers' do
resources :extensions, shallow: true
end
end
# Ajax call
get 'servers/:id/extensions/get_company_employees', to: 'servers/extensions#get_company_employees', as: 'get_company_employees'
app/controllers/servers/extensions_controller.rb
class Servers::ExtensionsController < ApplicationController
def get_company_employees
#server = Server.find(params[:id])
#extension = #server.extensions.build
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.where("company_id = ?", params[:company_id])
respond_to do |format|
format.js
end
end
def new
#server = Server.find(params[:server_id])
#extension = #server.extensions.build
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.none
end
def create
#server = Server.find(params[:server_id])
#extension = #server.extensions.build(extension_params)
#extension.password = "pass"
if #extension.save
flash[:success] = "Successfully created extension"
redirect_to #extension
else
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.none
flash.now[:error] = "Failed to create extension"
render "new"
end
end
private
def extension_params
params.require(:extension).permit(:value, :password, :employee_id, :server_id, :phone_id)
end
end
app/views/servers/extensions/_form.html.erb
<%= form_for(#path) do |f| %>
<p>
<%= label_tag(:company) %>
<%= select_tag "company", options_from_collection_for_select(#companies, "id", "name"), include_blank: "Select a company" %>
</p>
<p>
<%= f.label(:employee) %>
<%= f.collection_select :employee_id, #employees, :id, :full_name, include_blank: "Select an employee" %>
</p>
<p>
<%= f.submit "Submit" %>
</p>
<% end %>
app/views/servers/extensions/get_company_employees.js.coffee
$("#extension_employee_id").empty()
.append("<option>Select an employee</option>")
.append("<%= j options_from_collection_for_select(#employees, :id, :full_name) %>")
app/assets/javascripts/servers/extensions.coffee
$ ->
$(document).on 'page:load', '#company', (evt) ->
$.ajax 'get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
$(document).on 'change', '#company', (evt) ->
$.ajax 'get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
Its because you have now specified complete URL in ajax call
It should be something like this in both cases.
$.ajax "/servers/"+ id +"/extensions/get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
// store and fetch id attribute from page in any of the dom element
Ideally you should write a function for your ajax call which can be called wherever required and code redundancy can be reduced.

Filter field based on previous field selection

How can I use simple_form to filter a field, based on a previous fields value?
For instance, I have an Opportunities form, with two fields, Company and Contact.
Company Field:
<div class="form-group">
<%= f.association :company, collection: Company.all.order(:account), prompt: "", :label_method => :account, :value_method => :id %>
</div>
Contact Field:
<div class="form-group">
<%= f.association :contact, collection: Contact.all.order(:first_name), prompt: "", :label_method => lambda { |contact| "#{contact.first_name} #{contact.last_name}" }, :value_method => :id %>
</div>
Here is what I want to do: If I select a company called "Deviant" from the Company field above, I want the Contact field to only display those contacts associated with the company called "Deviant".
I am trying something like this, but can't get it to work:
<div class="form-group">
<%= f.association :contact, collection: Contact.where("company_id = ?", params[:id]), prompt: "", :label_method => lambda { |contact| "#{contact.first_name} #{contact.last_name}" }, :value_method => :id %>
</div>
I don't know how to reference the value in the Company field.
How can I do this?
Thanks.
Update
Anyone? Surely this must be possible. This is a key functionality in any form. I would hope I don't need jQuery or something.
I think the best approach is to use ajax requests to update your contacts collection dinamically whenever the company's selected value is changed.
First you'll need an action in your contacts controller:
app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def contacts_list
if params[:company_id]
#contacts = Contact.where(company_id: params[:company_id])
else
#contacts = Contact.all
end
respond_with(#contacts) do |format|
format.json { render :json => #contacts.to_json(:only => [:id, :first_name, :last_name]) }
end
end
end
Add this to your routes:
config/routes.rb
post 'contacts_list' => "contacts#contacts_list", as: :contacts_list
Then use the coffeescript code bellow to populate your contacts' collection:
app/assets/javasctipts/companies.js.coffee
$(document).ready ->
if $("#opportunity_company_id")
populate_contacts()
$("#opportunity_company_id").change ->
populate_contacts()
populate_contacts = ->
$contacts_select = $("select#opportunity_contact_id")
$contacts_select.attr "disabled", "disabled"
company_id = $("select#opportunity_company_id").val()
if company_id is ""
$contacts_select.html "<option value=\"\">(select the company first)</option>"
else
$contacts_select.html "<option value=\"\">(loading contacts...)</option>"
data = {company_id: company_id}
data[window._auth_token_name] = window._auth_token
$.ajax "/contacts_list",
type: "post"
dataType: "json"
data: data
success: (contacts) ->
_html = '<option value="">Select the contact:</option>'
_html += '<option value="'+contact.id+'">'+contact.first_name + ' ' + contact.last_name + '</option>' for contact in contacts
$contacts_select.html _html
$contacts_select.removeAttr "disabled"
error: ->
alert 'Error trying to load contacts.'
Finally, inside your html's head tag:
<% if protect_against_forgery? %>
<script>
window._auth_token_name = "<%= request_forgery_protection_token %>";
window._auth_token = "<%= form_authenticity_token %>";
</script>
<% end %>
Hope it helps...
update:
Add the following line to your ApplicationController (app/controllers/application_controller.rb):
respond_to :html, :xml, :json, :js

refreshing a partial's variables with ajax

Rails 3.2
jQuery-Rails
I've searched all over and I've only found js ways to update a partial or add a partial via JS. I've had no luck with this one. Here is the issue:
I have a list of referrals on a page, the referrals are posted on the index page as partials. The referral box has a reply button and a count of how many replies per referral. Statically I had it working but I'm getting no luck with updating the referral box with the new count and replacing the reply button with an icon. The is getting to the database but I'm screwing something up with the refresh of the box. Help please!
Do I use locals to render the new variables?
Should I remove my if statements from the partial and just use the js.erb file to determine what to show?
Reply controller:
class RepliesController < ApplicationController
respond_to :html, :js
def new
#referral = Referral.find(params[:referral_id])
#reply = #referral.replies.new(:user_id => params[:user_id], :referral_id => params[:referral_id])
if #reply.save
format.html { notice: 'Replied' }
respond_with(#referral, :location => referrals_path)
end
end
end
_referral partial:
.referralBox.cornerShadow{:id => "Referral#{referral.id}"}
- if current_user == referral.user or current_user.role == 'administrator'
= link_to '<i class="icon-pencil icon-large icon-grey" rel="tooltip" title="Edit"></i>'.html_safe, edit_referral_path(referral), class: "referralEdit"
= link_to '<i class="icon-remove icon-large icon-grey" rel="tooltip" title="Delete"></i>'.html_safe, referral, method: :delete, data: { confirm: 'Are you sure?' }, class: "referralClose"
.referralProfile
= link_to "#{image_tag(referral.user.image.url, :class => "img-circle img-border border-white", :style => "thumb")}".html_safe, referral.user
%ul.unstyled.inline
%li
= referral.description
- unless referral.replies.count == 0
- if referral.user == current_user
%i.icon-comments.icon-large{"rel" => "tooltip", "title" => "Replies"}
= referral.replies.count
- else
%i.icon-comments.icon-large.orange{"rel" => "tooltip", "title" => "Replies"}
= referral.replies.count
- unless current_user == referral.user
- if referral.replies.any?
%i.icon-ok.icon-large.pull-right.orange{"rel" => "tooltip", "title" => "Replied"}
- else
= link_to '<i class="icon-ok icon-large pull-right icon-grey" rel="tooltip" title="Reply"> Reply</i>'.html_safe, new_referral_reply_path(:referral_id => referral.id, :user_id => current_user.id), :id => "ReplySubmit", :remote => true
new.js.erb view
$(".referralBox").html("<%= j(render(:partial => "#referral")) %>");
application.js
jQuery.ajaxSetup({
'beforeSend': function (xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
});

Resources