NoMethodError/Undefined Method While Trying To Use Stripe In Partial - ruby-on-rails

I'm implemented Stripe into my app but I'm attempting to move my "Upgrade Membership" option into a partial. I put the code within a partial and attempted to use the partial in my users#show view and the page won't load correctly and it gives me the error listed below. When I visit my charges#new view (which was the default view I set up prior to attempting to move everything over to my users#show view), the view loads and with no problem. But when I throw it in the partial and try to use the partial in my users#show, I get a NoMethodError/Undefined Method and I can't seem to figure out why.
Below is the error and my code (I added a comment on the line that's highlighted in the error message). Please let me know if any other code/info needs to be added. Thank you in advance for any help!
Error
NoMethodError in Users#show
undefined method `[]' for nil:NilClass
<h4>Upgrade To Premium</h4>
<script class='stripe-button' src="https://checkout.stripe.com/checkout.js"
data-key="<%= #stripe_btn_data[:key] %>" #highlighted line in the error
data-amount=<%= #stripe_btn_data[:amount] %>
data-description="<%= #stripe_btn_data[:description] %>"
data-email="<%= current_user.email %>" >
_form Partial
<% if current_user.premium? %>
<%= render partial: "charges/downgrade" %>
<% else %>
<%= form_tag charges_path do %>
<h4>Upgrade To Premium</h4>
<script class='stripe-button' src="https://checkout.stripe.com/checkout.js"
data-key="<%= #stripe_btn_data[:key] %>"
data-amount=<%= #stripe_btn_data[:amount] %>
data-description="<%= #stripe_btn_data[:description] %>"
data-email="<%= current_user.email %>" >
</script>
<% end %>
<% end %>
Users#show
<div class="container">
<h2><%= #user.email %></h2>
<% #wikis.each do |wiki| %>
<ul>
<li><%= link_to wiki.title, #wiki %></li>
</ul>
<% end %>
</div>
<br />
<div class="container">
<%= render partial: "charges/form" %>
</div>
I have another partial that I'm using within the partial that I'm having an error with, not sure if it's related but here it is just in case.
Downgrade Partial
<%= button_to 'Downgrade Membership', user_downgrade_path(current_user), class: 'btn' %>
Charges Controller
class ChargesController < ApplicationController
def create
# Creates a Stripe Customer object, for associating with the charge
customer = Stripe::Customer.create(
email: current_user.email,
card: params[:stripeToken]
)
charge = Stripe::Charge.create(
customer: customer.id, # Note -- this is NOT the user_id in your app
amount: 15_00,
description: "Premium Membership - #{current_user.email}",
currency: 'usd'
)
current_user.update_attributes!(role: 'premium')
flash[:notice] = "Thank you for upgrading to a Premium Membership, #{current_user.email}!"
redirect_to root_path # or wherever
# Stripe will send back CardErrors, with friendly messages
# when something goes wrong.
# This 'rescue block' catches and displays those errors.
rescue Stripe::CardError => e
flash[:alert] = e.message
redirect_to new_charge_path
end
def new
if user_signed_in?
#amount = 15_00
#stripe_btn_data = {
key: "#{ Rails.configuration.stripe[:publishable_key] }",
description: "BigMoney Membership - #{current_user.email}",
amount: #amount
}
else
redirect_to root_path
flash[:notice] = "You must be signed in to do that."
end
end
end

Ended up being something stupid and easy. I needed to define #stripe_btn_data within my user_controller since I'm using the partial in a user view.

Related

Allow user to complete form with a delay, error : undefined method `errors' for nil:NilClass

I try to allow user to fill the form with a delay between each user,
The delay is set to 100 between the last user registered in my database and the new one
Here is what I do in my controller :
class EmailsController < ApplicationController
def index
redirect_to root_path
end
def new
#email = Email.new
end
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
format.html{render :new, notice: "Wait !"}
end
else
respond_to do |format|
#email = Email.create(email_params)
if#email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validated '}
else
format.html{render :new}
end
end
end
end
private
def email_params
params.require(:email).permit(:email, :id_user)
end
end
My view :
<div class="container">
<% if flash[:notice].present?%>
<center><p id="notice" class="alert alert-success"><%= flash[:notice] %></p></center>
<%end%>
<center><h1>Nouvelle Connection </h1></center>
<%= form_with model: #email, local: true do |form|%>
<% if #email.errors.any? %>
<div id="error explanation" class="alert alert-danger">
<p>Erreur(s) : </p>
<ul>
<% #email.errors.full_messages.each do |message|%>
<li><%=message%></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= label_tag :email %> :
<%= form.email_field :email, placeholder: "Insérez votre email", class: "form-control" %>
</div>
<div class="form-group">
<%= form.submit class: "btn btn-primary btn-lg btn-block", value: "Se connecter" %>
</div>
<%end%>
</div>
When I fill the form, nothing happen, just the url change from http://localhost:3000/ to http://localhost:3000/emails and when I re-click on Validate, it goes to http://localhost:3000/emails/53 with the error The action 'update' could not be found for EmailsController but I guess I have this error because I don't have any update/edit in my controller.
Do you know how to fix that to allow me a delay between each user ?
Edit : I now have the error undefined method errors for nil:NilClass in my view at the line <% if #email.errors.any? %>. I understand this is because my #email is nil but I tried to integrate this in my view :
<% if #email.nil?%>
<%= Wait for the moment %>
<%end%>
Also tried : <% if #email&.errors&.any? %> why so, I return to the URL : http://localhost:3000/emails
But still have the same error, do you know how to fix it ?
First off, in your view you check for notice.present? and that should be flash[:notice].present?. So then the error will be shown.
Secondly, in your controller you are actually first creating the email, and only then checking if it should be created, and then not even removing it? So the only result is that people will see a notice, but the email would still be created.
So instead do something like:
def create
if Time.now - Email.last.created_at < 100
respond_to do |format|
#email = Email.new(email_params)
format.html do
flash[:notice] = 'Wait! You cannot enter emails so quickly!'
render :new
end
end
else
respond_to do |format|
#email = Email.create(email_params)
if #email.persisted?
format.html {redirect_to invoice_index_path, notice: 'Email validé '}
else
format.html{render :new}
end
end
end
end
Secondly this does seem to mean that any user wanting to enter a new email, will be punished if another user has also entered another email. So in that case you might want to check as follows:
Email.where(created_by_id: current_user.id).last
to only check for Email 's the current user has entered (but maybe that is taking your problem/solution too far?).
Also note there are much better/efficient ways to throttle requests (rate limiting) using apache/nginx (which is probably how it will be deployed), so is this actually a good approach to handle in your ruby on rails code?

Stripe iFrame being blocked - rails and stripe

I am making a checkout form with stripe and rails. I have a shop_controller that serves a list of products in the shop#index. Then that leads to the shop#show where the stripe form is located, and users can purchase a product.
Right now when clicking the button to make a purchase (using the fake card stripe gives you), all that happens is the button endlessly spins, and I get the following errors in the console:
GET https://checkout.stripe.com/api/account/lookup?email=MYEMAILADDRESS&key=&locale=en-US 400 (Bad Request)
and
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://localhost:3000" from accessing a frame with origin "https://checkout.stripe.com". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "https". Protocols must match.
When I am adding my email to the form, I am also getting this error:
The specified value "MYEMAILADDRESS" is not a valid email address.
Here is my set up
routes.rb
resources :shop
shop_controller
class ShopController < ApplicationController
def index
#products = Product.all
end
def show
#product = Product.find(params[:id])
end
def new
end
# the create happens in the show action
def create
#product = Product.find(params[:id])
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #product.price * 100,
:description => #product.description,
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
show.html.erb (where the form is rendered to pay)
<div class='shop-show'>
<div class="container">
<div class="row text-center">
<div class="col-lg-12 col-xs-12">
<h2><%= #product.name %></h2>
<hr class="generic">
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="white_panel">
<%= form_for #product, url: url_for(controller: 'shop', action: 'create' ) do %>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<script src="http://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="<%= #product.description %>"
data-amount="<%= #product.price * 100 %>"
data-locale="auto"
data-shipping-address=true>
</script>
<% end %>
<img class="img-responsive" width='400' height='250' src="<%= #product.pictures.first.image.url %>">
<h2><%= #product.description %></h2>
</div>
</div>
</div>
</div>
</div>
Has anyone set up this kind of functionality before? This was closely followed using the link provided by stripe: https://stripe.com/docs/checkout/rails. Any help with this set up would be very appreciated. Thanks.
The Checkout ctript tag's URL there needs to be retrieved over HTTPS. Try swapping this:
<script src="http://checkout.stripe.com/checkout.js"
for this:
<script src="https://checkout.stripe.com/checkout.js"

Rails/Bootstrap - Flash notice :success is now red and not green?

I've been trying to search for an answer on here but I can't find anything that works. I have implemented a :success and :danger flash notice to my rails app. It WAS working completely fine, i.e :success was green and :danger was red, with a close button and all, BUT since adding some mailer files my :success is now showing up red??
application.html.erb excerpt:
<body>
<div class="container">
<% flash.each do |key, value| %>
<%= content_tag :div, class: "alert alert-#{key == 'notice ? 'success' : 'danger'}" do %>
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<%= value %>
<% end %>
<% end %>
<%= yield %>
</div>
</body>
contact_mailer.rb
class ContactMailer < ActionMailer::Base
default to: 'justindavidson23#gmail.com'
def contact_email(name, phone, email, event_type, body)
#name = name
#phone = phone
#email = email
#event = event_type
#body = body
mail(from: email, subject: 'Contact Form Message').deliver
end
end
contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
if #contact.save
name = params[:contact][:name]
phone = params[:contact][:phone]
email = params[:contact][:email]
event = params[:contact][:event_type]
body = params[:contact][:comments]
ContactMailer.contact_email(name, phone, email, event, body).deliver
flash[:success] = 'Message Sent.'
redirect_to new_contact_path
else
flash[:danger] = 'Error occurred, messgage not sent.'
redirect_to new_contact_path
end
end
end
private
def contact_params
params.require(:contact).permit(:name, :phone, :email, :event_type, :comments)
end
and, contact_email.html.erb
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>New Message from Hoot and Holla's Contact form, from <%= "#{#name}, #{#email}" %></p>
<p><%= #phone %></p>
<p><%= #event %></p>
<p><%= #body %></p>
</body>
</html>
I repeat that this was all working completely fine before the mailer stuff went in...but now i'm just baffled. Please help!
Sometimes you are going to want to use more than notice and success, like the Bootstrap alerts info, danger, and warning.
Here is the solution I would recommend:
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %> alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<%= value %>
</div>
<% end %>
That way, when you call flash[:success] = 'foo', your key would be success, and likewise for info, warning, danger, etc. This way you can utilize all of the different Bootstrap alerts.
With this method, you will have to add 2 more CSS classes, that extend the Bootstrap classes, if you want to use the syntax notice: 'hello world', or alert: 'oops' in your redirections, like redirect_to root_url, notice: 'welcome home'.
If you do want to use these, then you can use Sass, like below.
.alert-alert {
#extend .alert-danger;
}
.alert-notice {
#extend .alert-warning;
}
Since my comment earlier on the mailer callback was more of a side note and unrelated to this question, I made a simple gist for ya.
In your flash loop, you are only checking flash[:notice] there. if there is flash[:notice], you applying alert-success. unless it applying alert-danger. So, what i change here. i am applying alert-success for both flash[:success] & flash[:notice]. So,
Do in _flash.html.erb -
<%= content_tag :div, class: "alert alert-#{['success','notice'].include?(key) ? 'success' : 'danger'}" do %>
Try this code in application layout...
<div id="wrapper">
<div id="page-wrapper">
<div class="row">
<div class="col-lg-12">
<% flash.each do |name, msg| %>
<%= content_tag(:div, msg, :id=>"#{name}", :class `enter code here`=>"alert alert- info") %>
<%end%>
</div>
</div>
</div>
</div>
<script type="text/javascript">
window.setTimeout(function()
{
$("#notice").fadeTo(500, 0).slideUp(500, function()
{
$(this).remove();
});
}, 5000);
</script>
<%= yield%>
Oh thanks so much #AmitSuroliya!! This has worked perfectly!! I'm trying to work out what is actually happening here in the code...i don't suppose you could give a short explanation as to why this works could you??...if not thankyou anyway!! I appreciate it so much :)
Justin
PS for people having the same problem and reading this....that solution was copying and pasting this into my application.html.erb file and replacing the content_tag line i had...NOT creating a partial called _flash.html.erb ..just incase anyone was getting confused there :)

Creating Subscription with stripe

I'm trying to create a subscription package using Stripe..
Here what I have so far
My controller method.
def subscription_one
session[:tab] = "$1.99/Month"
#subscription = Subscription.where(user_id:current_user.id)
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
subscription_one.html.erb
<% if #subscription.present? %>
CREDIT CARD DETAILS PRESENT
<% else %>
<form action="/membership/apply" method="POST" id="payment-form">
<article>
<label class="amount"> <span>Amount: $5.00</span> </label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
After I give all values in fields that appear, when I submit I get an error
ActionController::InvalidAuthenticityToken in MembershipController#create
Any ideas?
Several issues:
--
Form
The form you've included is hard coded
The problem you have is, as stated by Philidor Green, this form won't have the correct authenticity token provided by Rails. As a rule of thumb, Rails provides helpers for most HTML elements, allowing you to create consistent code for your app:
<%= form_tag path do %>
<% end %>
You should use form_tag for this
--
Subscription
Subscription.new(params[:subscription])
Should be:
def subscribed_one
Subscription.new(subscription_params)
end
private
def subscription_params
params.require(:subscription).permit(:params, :attributes)
end
--
Update
To handle this, I'd do this:
#view
<% if #subscription.present? %>
Credit Card Details Present
<% else %>
<%= form_tag membership_apply_path, id: "payment-form" do %>
<%= content_tag :article do %>
<%= label_tag class: "amount" %>
<%= content_tag :span, "Amount: $5.00" %>
<% end %>
<% submit_tag "Susbcribe" %>
<% end %>
<% end %>
#app/views/layouts/application.html.erb
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500">
</script>
#app/controllers/subscriptions_controller.rb
def subscription_one
session[:tab] = "$1.99/Month"
#subscription = Subscription.where(user_id:current_user.id)
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
I found a workaround, maybe to simple to be honest, it's the standard stripe checkout, replacing standart Form element by for_path. It seems working :
<%= form_tag stripe_user_standart_charge_checkout_path do %>
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="..."
data-amount="999"
data-name="Grégoire Mulliez"
data-description="Timee"
data-zip-code="true"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-locale="auto"
data-currency="eur">
</script>
<% end %>
stripe_user_standart_charge_checkout_path is whatever route you want, don't forget to define it as POST (not get) in your routes.rb
Edit : you can retrieve hour transaction token using this method, also I added some html hidden fields to revrieve and the same time my transaction details , it's working like a charme

Rails - error messages can't be displayed

When I send wrong email, validation can't pass but error messages in views don't be displayed :(
I have in models:
validate :recipient_not_have_invitation, :notice => "That user have already invitation"
def recipient_not_have_invitation
errors.add :notice, 'That user have already invitation' if InvitationToGroup.find_by_recipient_email_and_group_id(recipient_email, group_id)
end
in controller:
(...)
if #invitation_to_group.save
Mailer.invitation_to_group(#invitation_to_group).deliver
redirect_to root_url, :notice => "Successfully send invitation to user #{#invitation_to_group.recipient_email}"
else
redirect_to new_invitation_to_group_path(:group_id => #invitation_to_group.group_id)
end
In views (invitation_to_groups/new.html.erb)
<h2>New Invitation to group </h2>
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<%= form_for #invitation_to_group do |f| %>
<% if #invitation_to_group.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#invitation_to_group.errors.count, "error") %> prohibited this user from being invitation:</h2>
<ul>
<% #invitation_to_group.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
(...)
The problem is that you are using redirect_to after else in your controller. So you are going to new action and in this action you have InvitationToGroup.new. So you build new object without errors ;) You need to use render method instesd.
PS. you should really consider using "formtastic". It will imporve your code in views. Please watch this two railscasts: http://railscasts.com/episodes/184-formtastic-part-1 and http://railscasts.com/episodes/185-formtastic-part-2

Resources