Javascript doesn't work on heroku in production - ruby-on-rails

I have a javascript code that should display image (loading gif) when you click to create a comment. It works in development, but not when I deploy it to heroku. I am able to make the most js/css files work properly, but not in this case.
<%= nested_form_for([#post, #comment], validate: true, html: {multipart: true}, 'data-update-target' => 'comments', class: 'comments') do |f| %>
...
<div class="actions">
<%= f.submit " Submit ", :class => "btn btn-default", :id => "submit" %>
</div><br>
<div id="loading2" class="loadinggif" style="display:none;"><img src="/assets/othericons/uploading.gif" alt="" /></div>
<script type="text/javascript">
(function (d) {
d.getElementById('new_comment').onsubmit = function () {
d.getElementById('submit').style.display = 'block';
d.getElementById('loading2').style.display = 'block';
};
}(document));
</script>
solution
I changed
<div id="loading2" class="loadinggif" style="display:none;"><img src="/assets/othericons/uploading.gif" alt="" /></div>
to
<div id="loading2" class="loadinggif" style="display:none;">
<%= image_tag("othericons/uploading.gif", alt: "") %>
</div>

With Heroku, I've only had success pre-compiling assets and adding those assets to git before deploying. When I start working on any assets in my dev environment, I run rake assets:clean and then when I'm done, rake assets:precompile; git add --all public/assets.

Related

Failed to execute 'postMessage' on 'DOMWindow' using Stripe on rails 7

I have integrated Stripe payment in my rails 7 app and the stripe form does not show.
when i check inspect element in browser, this error shows:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://js.stripe.com') does not match the recipient window's origin ('http://localhost:3000').
purchases/show.html.erb
<h1>Purchase <%= #product.name %></h1>
<%= form_with url: product_purchase_path(#product), local: true, id: "payment-form", data: { payment_intent_id: #payment_intent.client_secret} do |form| %>
<div class="form-group">
<label for="card-element">Credit or debit card</label>
</div>
<div id="card-element" class: "form-control">
</div>
<div id="card-errors" role="alert"></div>
</div>
<div class="form-group">
<label>Name on Card</label>
<%= form.text_field :name_on_card, placeholder: "Full Name", class: "form-control" %>
</div>
<div class="form-group">
<%= form.hidden_field :payment_intent_id, value: #payment_intent.id %>
<button class="btn btn-primary">Submit Payment</button>
</div>
<% end %>
Application.js
document.addEventListener("turbo:load", () => {
const public_key = document.querySelector("meta[name= 'stripe-key']").getAttribute("content")
const stripe = Stripe(public_key)
const elements = stripe.elements()
const card = elements.create('card')
card.amount('#card-element')
card.addEventListener("change", (event) => {
var displayError = document.getElementById('card-errors')
if (event.error) {
displayError.textContent = event.error.message
} else {
displayError.textContent = ''
}
})
})
This there any solution for this?
That's because Stripe only allows https connections for security reasons. To resolve this issue you either serve your app over https or you can use a Tool such as ngrok
Download and install ngrok from the official website (https://ngrok.com/)
Start your rails app rails serve
Start ngrok by running the following command in a seperate window
ngrok http 3000
This will start a secure public url (e.g. https://your-unique-subdomain.ngrok.io ) that you can use to access your local development environment. Use this URL in your Stripe form and try accessing the page again.

Why google storage don't accept direct uploads from Rails Active Storage?

I'm using google cloud storage in my application. Until last week everything were working fine, i've change nothing and now my files aren't beeing sent to storage.
The following message is displayed when I submit the form with the file.
and in the console has a link that display this
One curious thing is that i can normally sent the images from Rails Console
config.logo.attach(io:File.open(Rails.root.join('public/images/default.png')), filename: 'default.png', content_type:'application/png');
If using local storage everything works fine too.
Using Ruby 2.5.1, Rails 5.2.2 and Active Storage with Direct Uploads.
UPDATE
My form
<%= form_for #config, multipart: true do |f| %>
<div class="row border-bottom white-bg dashboard-header">
<div class="col-lg-12">
<h2>Configs</h2>
</div>
<div class="col-lg-12 mb-lg-5">
<%= image_tag f.object.logo, clas: 'img-fluid' if f.object.logo.attached? %>
<div class="form-group">
<%= f.label :logo %>
<%= f.file_field :logo, direct_upload: true, class:"form-control form-resource" %>
</div>
<button type="submit" class="btn btn-block btn-primary">Salvar</button>
</div>
</div>
<% end %>
When I remove direct_upload: true, works fine, but I don't want remove this functionality
Solved by configuring CORS (Cross-Origin Resource Sharing)
https://cloud.google.com/storage/docs/cross-origin

Render partial through js.erb

Im trying to render a form to add a comment via jquery, but i keep getting this error:
undefined method `render' for #<#<Class:0x007fc8aaa18860>:0x007fc8a0fddfc0>
Here is the js.erb file:
$(document).on('turbolinks:load', function(){
console.log('test');
$('.reply-comment-form').on('click', function(e) {
e.preventDefault();
body = this.id;
$('.nest-' + body).append( "<%= escape_javascript(render partial: 'comment_reply_form')%>");
});
});
Ive tried multiple different iterations of the code but still the same error.
When i try say, this for example:
$('.nest-' + body).append( " This is a test");
It does as it should do.
Ive checked the other questions here and i cant see anything different to what i'm doing so i'm a little stuck.
Here is what im trying to render:
<div class="body">
<span class="tip tip-left"></span>
<div class="message font-medium">
<%= form_for #message do |form| %>
<%= form.label :Reply_to_comment %> <br />
<%= form.text_area :content, :rows => 5, :cols => 80, autofocus: true %> <br />
<%= form.hidden_field :entry_id, value: params[:entry_id] %>
<%= form.hidden_field :parent_id, :value => params[:parent_id] %>
<%= form.submit "Submit"%>
<% end %>
</div>
<div class="flerowspb">
<span class="font-small">
</span>
</span>
</div>
</div>
Thanks
Ok so I've come across the answer, I cant call render from the assets folder.
Here is the link
Try to the following
$('.nest-' + body).append( "<%= escape_javascript(render("messages/comment_reply_form"))%>");
or
$('.nest-' + body).html("<%= escape_javascript(render("messages/comment_reply_form")) %>");
Try using j render:
$('.nest-' + body).append( "<%= j render 'comment_reply_form' %>");
and i think that path for partial view should be more accurate, like 'controller_name/view/partial' , or whatever you have in your code.

Confused about how to properly use secret keys

So in my quest to get Stripe integrated, I find myself confused about how to properly use secret keys and environmental variables. To my understanding, I do NOT want to explicitly include my secret key in any public place and should be using a environmental variable instead. But it does not seem to work when I substitute the ENV in place of the actual hardcoded key. I am doing something wrong, but what? Here is what I have. In my secret.yml file:
development:
secret_key_base: xxxxxxxxxxxxxxx
secret_key: sk_test_JlKC4V7nmCQ0sE4iNAVyoAxA
publishable_key: pk_test_KfCg1YmVXwBYyEdPEWnfibF8
stripe_live_publishable_key: pk_live_pxxxxxxxxxxxxxx
stripe_live_secret_key: sk_live_jxxxxxxxxxxxxx
test:
secret_key_base: a38exxxxxxxxxxxxxxxx
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
#test
secret_key: <%= ENV["SECRET_KEY"] %>
publishable_key: <%= ENV["PUBLISHABLE_KEY"] %>
# live
stripe_live_publishable_key: <%= ENV["STRIPE_LIVE_PRODUCTION_KEY"] %>
stripe_live_secret_key: <%= ENV["STRIPE_LIVE_SECRET_KEY"] %>
and in /initialize/stripe.rb I have:
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
and in my payment form, I have the line:
Stripe.setPublishableKey('<%= 'sk_test_JlKC4V7nmCQ0sE4iNAVyoAxA'%>');
It works like this, but unless I am misunderstanding, is insecure (well, right now it is just a test key, but I need to know this when I use live keys for production). Yet when I try to use:
Stripe.setPublishableKey('<%= ENV['PUBLISHABLE_KEY'] %>');
I get the error:
Uncaught Error: You did not set a valid publishable key. Call Stripe.setPublishableKey() with your publishable key.
or when I try:
Stripe.setPublishableKey('<%= :publishable_key %>');
I get an error 401 (Unauthorized) in console.
How am I supposed yo be using the ENV[KEY] so that I do not need my key written out in plain sight?
UPDATE:
Here is my form where the key would be most public:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Contribution Form</title>
<!-- The required Stripe lib -->
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<!-- jQuery is used only for this example; it isn't required to use Stripe -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
// This identifies your website in the createToken call below
Stripe.setPublishableKey('STRIPE_TEST_PUBLISHABLE_KEY'); //<====How should this line look?
var stripeResponseHandler = function(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and re-submit
$form.get(0).submit();
}
};
jQuery(function($) {
$('#payment-form').submit(function(e) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken({
number: $('.card-number').val(),
cvc: $('.card-cvc').val(),
exp_month: $('.card-expiry-month').val(),
exp_year: $('.card-expiry-year').val()}, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
</script>
</head>
<body>
<!-- form -->
<div class="container">
<div class="row Row one">
<div class="col-sm-12 col-md-10">
<h1>Make your contribution</h1>
<%= form_for #project, url: project_charges_path, :html => {:id => "payment-form"}, method: 'post' do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :#project_id, :value => #project.id %>
<div class= "field">
<%= label_tag :card_number, "Credit Card Number" %><br>
<%= text_field_tag :card_number, nil, name: nil, class: ' card-number form-control', :required => true %><br>
</div>
<div class= "field">
<%= label_tag :card_code, "Security Code (cvc)" %><br>
<%= text_field_tag :card_code, nil, name: nil, class: 'card-cvc form-control', :required => true %><br>
</div>
<div class= "field">
<%= label_tag :card_month, "Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, class: "card-expiry-month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, class: "card-expiry-year"}%>
</div>
<div class= "field">
<%= label_tag :amount, "Amount" %><br>
<%= text_field_tag :amount %>
</div>
<div class= "field">
<%= label_tag :comments, "Add a comment?" %><br>
<%= text_area_tag :comments %>
</div>
<div class= "actions">
<%= f.submit 'Submit', :class => 'contribution-submit' %>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<% end %>
</div>
</div>
<!-- <div class="row"></div> -->
</div>
</body>
</html>
Environment variables in production have more to do with the application server than with your rails app. To me it looks like everything you've done seems correct , just need to set the variables in production mode.
For Heroku:
heroku config:set STRIPE_PERISHABLE_KEY=<your key here>
heroku config:set STRIPE_SECRET_KEY=<your key here>
For Passenger (nginx or apache):
In your server/site definition with passenger you can add passenger environment variables.
passenger_env_var STRIPE_PERISHABLE_KEY '<your key here>';
passenger_env_var STRIPE_SECRET_KEY '<your key here>';
*Note that with Apache you use an = sign between the key and the value and there are no quotes around the value.
ENV variables are set via terminal. This isn't the 'best practice' but I set my keys in my .bash_profile. There are also gems that manage your env-vars for you.
Here is a popular one that implements yaml:
https://github.com/laserlemon/figaro
Here is an example of adding keys to your .bash_profile
## Work Keys
export STRIPE_KEY="pk_test_somekey"
export STRIPE_SECRET="sk_test_somekey"
Then in ruby you can access the variable like this:
ENV["STRIPE_KEY"]
ENV["STRIPE_SECRET"]
You need to refresh your environment after doing this by making a new terminal instance. So quit terminal and restart your server!

How to save ids in the cookies

I am using will_paginate to list a huge ammont of files in different pages. I also have a check_box in order to choose files for the futher analysis.
controller:
#files = FileDB.search(search_string).paginate(:per_page => 10, :page => params[:page])
view:
<button type="button" id="check_all">Check/Uncheck all</button>
<%= button_tag :class => "btn btn-primary", :name => 'analyse' do %>Analyse<% end %>
<% #filess.each do |file| %>
<p><td> <%= check_box_tag "files[]", file.id %></td><%= file.name %></p>
lala...
My problem is that I can choose the files which are situated in one page.So by clicking on "check/uncheck all" it checks not all available files, but files of this specific page. I would like to be able to check different files from different pages together.
Example: 10 files on the page 1, 4 files on the page 2. I want to check 5 files from page one and all files from page 2 and then by clicking on the buttom "Analyse", those 9 files have to be analyzed together, so the checkbox should remember different files from different pages
I know it is possible to save ids in the cookies, but I have found nothing in internet how to do it. I need just a small example
Thanks in advance
edit:
or maybe there is an alternative to the will_paginate that uses POST?
edit2: according to Muntasim
<script type='text/javascript'>
$('#check_all').on("click", function(){ $('input[type="checkbox"]').click(); });
</script>
<script src="/assets/rails.validations.js" type="text/javascript"></script>
<script src="/assets/jquery.cookie.js" type="text/javascript"></script>
<script type="text/javascript">
var checkedIds = $.cookie('checked_file_ids');
$('p td input[type=checkbox]').on('change', function () {
if($(this).is(':checked')) {
checkedIds.push($(this).val())
}
else {
checkedIds.splice(checkedIds.indexOf($(this).val()), 1);
}
$.cookie('checked_file_ids', checkedIds);
})
</script>
<%= form_for Group.new, url: what_to_do_files_path ,method: :get ,:validate => true do |f| %>
<div class="field">
<%=f.text_field :group_name, placeholder: "Group Name" %>
</div>
<%= button_tag :class => "btn btn-primary", :name => 'analyse' do %>Analyse<% end %>
<button type="button" id="check_all" class="btn"> Check/Uncheck All</button>
<% #files.each do |file| %>
<p><td> <%= check_box_tag "files[]", file.id , false %></td><%= file.name %></p>
<%end%>
<%end%>
And in a controller:
def what_to_do
ids_to_compare = cookies['checked_file_ids']
end
But ids_to_compare is empty
You can simply do:
cookies[:ids] = #All checked ids
And then to retrieve the ids you can easily call the cookie like this:
cookies[:ids]
if you want to use cookie:
use jquery.cookie
Now put this in the view
<script type="text/javascript">
var checkedIds = $.cookie('checked_file_ids');
$('p td input[type=checkbox]').on('change', function () {
if($(this).is(':checked')) {
checkedIds.push($(this).val())
}
else {
checkedIds.splice(checkedIds.indexOf($(this).val()), 1);
}
$.cookie('checked_file_ids', checkedIds);
})
</script>
now when you need to compare them you can get the ids: (likely in a controller)
ids_to_compare = cookies['checked_file_ids']

Resources