Interaction between ruby and js in rails - interesting moment - javascript

So, there is method in conroller:
def create
email=params[:email]
email=email.downcase
user = User.find_by_email(email)
if user && user.authenticate(params[:password])&& user.confirmed
if session[:was_going]
#url=session[:was_going]
session[:was_going]=nil
end
#status=true
cookies[:auth_token] = {:value => user.auth_token, :expires => Time.now + 30.days }
elsif user && !user.confirmed
#status=false
#unconfirmed=true
else
##unconfirmed=false commented line
#status=false
end
respond_to do |format|
format.js{[#status, #url]}
end
end
It responds to format.js. On any case of authentication process I have boolean variable, which I pass to JS - #status (authenticated or not), #unconfirmed - special message, and just invalid input (if both #status and #unconfirmed are false). Pay attention to commented line.
Here is js template:
if(<%=#status %>) {
window.location.replace("<%= #url %>")
}
else {
if (<%=#unconfirmed %>) {
$('.sign_in').replaceWith("<%= j render :file=> 'signs/index.html.erb' %>")
$('.signs_form').prepend("<div id='errors_of_sign'> Check your mailbox on <br /> confirmation letter </div> ")
$('.signs_form').css({"margin-top":"30px"})
$('.facebook_sign').css({"margin-top":"80px"})
$('.sign_in').fadeIn('fast')
}
else{
$('.sign_in').replaceWith("<%= j render :file=> 'signs/index.html.erb' %>")
$('.signs_form').prepend("<div id='errors_of_sign'> Email or password are incorrect </div> ")
$('.signs_form').css({"margin-top":"30px"})
$('.facebook_sign').css({"margin-top":"80px"})
$('.sign_in').fadeIn('fast')
}
}
And there was trouble - when there was no commented line, the code for else statement didn't work at all.
Then I added that line, and now everything works.
Can you please explain this behaviour of JS? I mean, if there is no variable #unconfirmed, than ruby should return nil, which equal to false in boolean functions of any language I know, including JS.

You are right about ruby that it will return nil , if not declared but JS doesn't know what nil is .
Js knows 'true' or 'false'
'nil' is not defined in JS.
Try it yourself on console

Related

Get different html with different buttons with AJAX

I got this menu on my website
%button.dropdown-button
.current-user{onclick:'showMenu()'}
%img.current-user-image{src:current_user.picture_url}
= current_user
%i.fa.fa-bars{'aria-hidden':true}
.dropdown-content
.menu-option{onclick:'showFilters()'}
Filter Transactions
%i.fa.fa-paper-plane{'aria-hidden':true}
.transaction-filters
.filter-option
My Transactions
%i.fa.fa-square-o
%a{href:'#'}
.menu-option
Balance History
%i.fa.fa-history{'aria-hidden':true}
%a{href:destroy_user_session_path}
.menu-option
Sign Out
%i.fa.fa-sign-out{'aria-hidden':true}
And I got this timeline with transactions
.timeline-container
- #transactions.each do |transaction|
.transaction-container
.transaction-header-container
.transaction-kudos-container
= "+#{transaction.amount}"
%span.currency
₭
.transaction-avatar-container
%div
= image_tag transaction.receiver_image, class:'avatar'
.transaction-body-container
.transaction-content
%span
= "#{transaction.sender.name}:"
%span.highlighted
= "+#{transaction.amount} ₭"
%span
to
%span.highlighted
= transaction.receiver_name_feed
%span
for
%span.highlighted
= transaction.activity_name_feed
%div
-#%button#like-button
-# Like
%span.post-time-stamp
= "#{distance_of_time_in_words(DateTime.now, transaction.created_at)} ago"
= paginate #transactions
They are both rendered on my index.html.haml
So when I click the div .filter-option.sent I want to change the code change from
- #transactions.each do |transaction|
to
- #all_transactions.each do |transaction|
to filter out the transactions of the current user without reloading the page.
These variables are defined in my controller
#transactions = Transaction.order('created_at desc').page(params[:page]).per(20)
#all_transactions = Transaction.all_for_user(current_user)
With in my model the method all_for_user
def self.all_for_user(user)
Transaction.where(sender: user).or(Transaction.where(receiver: user)).order('created_at desc').page.per(20)
end
I tried a lot of things with AJAX but nothing seems to please me. Somebody can help me?
So if you'd like to replace that #transactions list with AJAX you will need to do a few things..
1) Move the #transactions block into a partial that takes a local variable.
#transactions-wrapper
= render partial: 'transactions/list', locals: {transactions: #transactions}
2) Create a link that submits to a route, that hits a controller action as #js ('data-remote': true ) ( or write a javascript function that triggers $.ajax request: https://www.w3schools.com/jquery/ajax_ajax.asp
%a.transaction-filter{href: "/transactions/#{transaction_type}", 'data-remote': true}
or ex..
%a.study{href: "/transactions/recent", 'data-remote': true}
%a.study{href: "/transactions/past", 'data-remote': true}
3) define the route
get '/transactions/:type' => 'transactions#filter'
4) re-assign the variable based on the filter, and re-render that partial with the new data in a filter.js.erb file thats in the view directory -> app/views/transactions
def filter
#filtered_transactions = Transactions.where(type: params[:type] ).order('created_at DESC')
respond_to do |format|
format.html
format.js { render :action => 'filter.js.erb', :layout => false}
end
end
$("#transactions-wrapper").html("<%= j render(:partial => 'transactions/list'', :locals => { transactions: #filtered_transactions } ) %>");
alert('Transactions have been filtered, yo')
Let me know if that makes sense! Except please don't actually javascript alert at the end ;)

jQuery updating rails form partial based on selected item in drop down

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.

Javascript multiple nested if statements don't work with Rails code

I have a method inside helper which fires an action which changes value of instance variable. Inside my javascript I've done this:
if(cat_id == 1)
{
<% cat_appointments(1) %>
}
else if(cat_id == 2)
{
<% cat_appointments(2) %>
}
else if(cat_id == 3)
{
<% cat_appointments(3) %>
}
My helper:
module StaticHelper
def cat_appointments(cat_id)
#appointments = Appointment.where(cat_id: cat_id)
end
end
The problems is that appointments are set like every time there is selected cat with id=3. If I put alert in those conditions, alert with selected id is displayed correctly when user selects specific cat.
Any ideas what is wrong with this code? How to change that variable?
When I replace:
else if(cat_id == 2)
{
<% cat_appointments(2) %>
}
with:
else if(cat_id == 3)
{
<% cat_appointments(3) %>
}
Then there are not always displayed appointments with cat_id=3. Now there are always displayed events with cat_id=2. So, the last 'else if' statement is always correct.
Thank you.
Can you try adding =
<%= cat_appointments(1) %>

jquery not loading (tokeninput) in Rails app

I'm trying to follow along with the instructions on how to implement jquery-tokeninput here:
How to use jquery-Tokeninput and Acts-as-taggable-on
I am trying to attach tags to a "post". I can use the text field in my form to create new tags. However, the javascript just will not fire at all. It's as if none of the code even exists. I don't get any error messages. The text field just acts as a normal text field with no javascript events firing. What can be the issue? Here is my relevant code:
post model
attr_accessible :tag_list
acts_as_taggable_on :tags
posts controller
def tags
query = params[:q]
if query[-1,1] == " "
query = query.gsub(" ", "")
Tag.find_or_create_by_name(query)
end
#Do the search in memory for better performance
#tags = ActsAsTaggableOn::Tag.all
#tags = #tags.select { |v| v.name =~ /#{query}/i }
respond_to do |format|
format.json{ render :json => #tags.map(&:attributes) }
end
end
routes
# It has to find the tags.json or in my case /products/tags.json
get "posts/tags" => "posts#tags", :as => :tags
application.js
$(function() {
$("#post_tags").tokenInput("/posts/tags.json", {
prePopulate: $("#post_tags").data("pre"),
preventDuplicates: true,
noResultsText: "No results, needs to be created.",
animateDropdown: false
});
});
Out of frustration I also created a posts.js.coffee file just to see if that was the problem:
$ ->
$("#post_tags").tokenInput "/posts/tags.json",
prePopulate: $("#post_tags").data("pre")
preventDuplicates: true
noResultsText: "No results, needs to be created."
animateDropdown: false
post form view
<%= f.label :tag_list %>
<%= f.text_field :tag_list, :id => "post_tags", "data-pre" => #post.tags.map(&:attributes).to_json %>
Am I missing something here? Any help would be greatly appreciated!!!
Thanks!!

how to use ajax with json in ruby on rails

I am implemeting a facebook application in rails using facebooker plugin, therefore it is very important to use this architecture if i want to update multiple DOM in my page.
if my code works in a regular rails application it would work in my facebook application.
i am trying to use ajax to let the user know that the comment was sent, and update the comments bloc.
migration:
class CreateComments < ActiveRecord::Migration
def self.up
create_table :comments do |t|
t.string :body
t.timestamps
end
end
def self.down
drop_table :comments
end
end
controller:
class CommentsController < ApplicationController
def index
#comments=Comment.all
end
def create
#comment=Comment.create(params[:comment])
if request.xhr?
#comments=Comment.all
render :json=>{:ids_to_update=>[:all_comments,:form_message],
:all_comments=>render_to_string(:partial=>"comments" ),
:form_message=>"Your comment has been added." }
else
redirect_to comments_url
end
end
end
view:
<script>
function update_count(str,message_id) {
len=str.length;
if (len < 200) {
$(message_id).innerHTML="<span style='color: green'>"+
(200-len)+" remaining</span>";
} else {
$(message_id).innerHTML="<span style='color: red'>"+
"Comment too long. Only 200 characters allowed.</span>";
}
}
function update_multiple(json) {
for( var i=0; i<json["ids_to_update"].length; i++ ) {
id=json["ids_to_update"][i];
$(id).innerHTML=json[id];
}
}
</script>
<div id="all_comments" >
<%= render :partial=>"comments/comments" %>
</div>
Talk some trash: <br />
<% remote_form_for Comment.new,
:url=>comments_url,
:success=>"update_multiple(request)" do |f|%>
<%= f.text_area :body,
:onchange=>"update_count(this.getValue(),'remaining');" ,
:onkeyup=>"update_count(this.getValue(),'remaining');"
%> <br />
<%= f.submit 'Post'%>
<% end %>
<p id="remaining" > </p>
<p id="form_message" > </p>
<br><br>
<br>
if i try to do alert(json) in the first line of the update_multiple function , i got an [object Object].
if i try to do alert(json["ids_to_update"][0]) in the first line of the update_multiple function , there is no dialog box displayed.
however the comment got saved but nothing is updated.
questions:
1.how can javascript and rails know that i am dealing with json objects?deos ROR sent it a object format or a text format?
2.how can i see what is the returned json?do i have to parse it?how?
2.how can i debug this problem?
3.how can i get it to work?
You have to parse the returned JSON in your javascript using a JSON parser.
Here is the one I use: https://github.com/douglascrockford/JSON-js/blob/master/json2.js
So upon success you'll do something like:
var stuff = json.parse(returnedJSON)

Categories