Mailchimp gem double_optin false not working - ruby-on-rails

double opt-in confirmation email still goes through, any idea what's wrong? Was having problems with the gibbon gem, so opted for mailchimp gem instead.
Gemfile
gem "mailchimp-api", "~> 2.0.4"
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :setup_mcapi
def setup_mcapi
#mc = Mailchimp::API.new('mailchimp api key goes here')
#list_id = "list id goes here"
end
end
welcome_controller.rb
class WelcomeController < ApplicationController
def index
end
def subscribe
email = params[:email][:address]
if !email.blank?
begin
#mc.lists.subscribe(#list_id, {'email' => email}, 'double_optin' => false)
end
respond_to do |format|
format.json{render :json => {:message => "Success!"}}
end
rescue Mailchimp::ListAlreadySubscribedError
respond_to do |format|
format.json{render :json => {:message => "#{email} is already subscribed to the list"}}
end
rescue Mailchimp::ListDoesNotExistError
respond_to do |format|
format.json{render :json => {:message => "The list could not be found."}}
end
rescue Mailchimp::Error => ex
if ex.message
respond_to do |format|
format.json{render :json => {:message => "There is an error. Please enter valid email id."}}
end
else
respond_to do |format|
format.json{render :json => {:message => "An unknown error occurred."}}
end
end
end
else
respond_to do |format|
format.json{render :json => {:message => "Email Address Cannot be blank. Please enter valid email id."}}
end
end
end
end
index.html.erb
<h3>Add a New Member</h3>
<p>Please enter your email address to subscribe to our newsletter.</p>
<%= form_tag('/welcome/subscribe', method: "post", id: "welcome", remote: "true") do -%>
<%= email_field(:email, :address, {id: "email", placeholder: "email address"}) %>
<%= submit_tag("Subscribe") %>
<% end %>
<div id="response">Response Will be displayed here</div>
routes.rb
Rails.application.routes.draw do
root 'welcome#index'
post 'welcome/subscribe' => 'welcome#subscribe'
end

From mailchimp-api document
subscribe(id, email, merge_vars = nil, email_type = 'html', double_optin = true, update_existing = false, replace_interests = true, send_welcome = false) ⇒ Hash
The double_optin is the parameter which will be passed directly not like what you did.
So, it will be:
#mc.lists.subscribe(#list_id, email, nil, 'html', false)

The answer above kept giving me errors, this worked for me:
#mc.lists.subscribe(#list_id, { "email" => email }, merge_vars = nil, email_type = 'html', double_optin = false)

Related

undefined method `stripe_id' for nil:NilClass

I am having this issue and each time I just remove stripe_id then I don't have the error but I get back to the home page without the payment working... Some freelancer did this part and I can't figure out why it doesn't work on my computer but works fine on a server or the freelancer's computer.. the code won't work on any of my computers.. Anybody knows what's the issue I been trying to figure this one out. On the server the payment works...
This is my controller
class SubscriptionsController < ApplicationController
protect_from_forgery :except => :webhooks
before_action :authenticate_user!, except: [:webhooks]
def new
end
# this is for recursive
def subscription_payment
begin
stripe_id = Plan.find_by_plan_type(params[:plan_type]).stripe_id
# stripe_id = Plan.find(params[:plan_id]).stripe_id
#plan = Stripe::Plan.retrieve(stripe_id)
customer = Stripe::Customer.create(
:description => "Customer for #{params[:stripeEmail]}",
:source => params[:stripeToken],
:email => params[:stripeEmail]
)
stripe_subscription = customer.subscriptions.create(:plan => #plan.id)
#payment = current_user.payments.new(customer_id: customer.id, card_exp_month: customer.sources[:data][0]['exp_month'], card_exp_year: customer.sources[:data][0]['exp_year'], card_id: customer.sources[:data][0].id, customer_subscription_id: stripe_subscription.id, plan_id: #plan.id)
#payment.save!
if params[:plan_type] == "monthly"
current_user.build_user_plan(plan_id: #plan.id, plan_expiry: Date.today+1.months).save
elsif params[:plan_type] == "annual"
current_user.build_user_plan(plan_id: #plan.id, plan_expiry: Date.today+1.years).save
else
current_user.build_user_plan(plan_id: #plan.id).save
end
flash[:notice] = 'You have successfully got the premium.'
redirect_to root_path
rescue Stripe::StripeError => e
flash[:error] = e.message
redirect_to root_path
end
end
# Method responsbile for handling stripe webhooks
# reference https://stripe.com/docs/webhooks
def webhooks
begin
event_json = JSON.parse(request.body.read)
event_object = event_json['data']['object']
#refer event types here https://stripe.com/docs/api#event_types
case event_json['type']
# when 'invoice.payment_succeeded'
# handle_success_invoice event_object
# when 'invoice.payment_failed'
# handle_failure_invoice event_object
# when 'charge.failed'
# handle_failure_charge event_object
when 'customer.subscription.deleted'
when 'customer.subscription.updated'
end
rescue Exception => ex
render :json => {:status => 422, :error => "Webhook call failed"}
return
end
render :json => {:status => 200}
end
end
This is my the sign in button where the amount is charged.
<% if user_signed_in? %>
<%= form_tag subscription_payment_path, method: :post do %>
<%= hidden_field_tag :plan_type, "monthly" %>
<script class="stripe-button"
data-amount="1000"
data-currency="CAD"
data-email="<%= current_user.email %>"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
src="https://checkout.stripe.com/checkout.js">
</script>
<% end %>
<% else %>
<a href="/users/sign_in" class="btn btn-neutral btn-round">
Subscribe
</a>
<% end %>
If you're seeing undefined method 'stripe_id' for nil:NilClass, then that means Plan.find_by_plan_type(params[:plan_type]) is likely returning nil. And you can't get the stripe_id of nil.
Are you sure that you have database records on your local machine, in particular Plan records with plan_type?
If your want to handle the scenario where a Plan is not found, given the plan_type, then you could try:
plan = Plan.find_by_plan_type(params[:plan_type])
raise SomeSortOfError if plan.nil? # make sure to rescue accordingly
stripe_id = plan.stripe_id

display braintree errors on fail

hi i am trying to get my braintree account to display errors when creating a transaction but it doesn't appear to be working
- flash.each do |key, value|
%div{:class => "alert alert-#{key}"}= value
def update
result = Braintree::Transaction.sale(
:amount => params[:amount_to_add].to_f,
# :order_id => "order id",
:customer_id => customer.customer_cim_id,
:tax_amount => (params[:amount_to_add].to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
if result.success?
logger.info "Added to #{params[:amount_to_add].to_f} to #{customer.first_name} #{customer.last_name} (#{customer.customer_cim_id})"
customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
result.errors.each do |error|
puts error.message
customer.errors.add(:base, error.message)
render :show, :notice => error.message
end
end
end
I believe the reason you're probably unable to see the errors is because of the :notice option on your render method, which is redundant because render doesn't seem to be using the :notice option, only redirect_to. You may just add the errors to your to your flash, but note that in your view you have to loop through the errors within the flash to render it.
Another way I would think you do this though is add the payment method to your User model
class User|Customer
...
def process_braintree_payment(amount)
result = Braintree::Transaction.sale(
:amount => amount.to_f,
# :order_id => "order id",
:customer_id => customer_cim_id,
:tax_amount => (amount.to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
add_braintree_errors(result.error) unless result.success?
end
def add_braintree_errors(error_object)
error_object.each do |error|
errors.add(:braintree, error.message)
end
end
end
class XController
def update
#customer.process_braintree_payment(params[:amount_to_add])
if #customer.errors.empty?
logger.info "Added to #{params[:amount_to_add].to_f} to #{#customer.first_name} #{#customer.last_name} (#{#customer.customer_cim_id})"
#customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
render :show
end
end
end
In your view, you have access to the #customer variable or better you could store the error object in the ActionController#flash, note however, using the same keys for your flash messages, would overwrite the previous value.

Rspec integration: param is missing or empty

I've got this Rails 4 controller like this:
class UsersController < ApplicationController
before_action :set_user, only: [:edit, :update, :delete]
# ...
api :POST, '/users', "Creates a new user"
param :username, String, :required => true, :desc => "Desired username"
param :email, /[a-zA-Z0-9\-.]+\#[a-zA-Z0-9\-.]+\.[a-z]{2,}/, :required => true, :desc => "User's e-mail address"
param :password, String, :required => true, :desc => "SHA256(username:password), hex encoded"
param :screenname, String, :required => true, :desc => "Publicly visible name"
param :avatar, String, :required => true, :desc => "Uploaded avatar filename"
error :code => 422, :desc => "Unprocessable entity"
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.json { render :show, status: :created, location: #user }
else
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# ...
private
# ...
def user_params
params.require(:user).permit(:username, :email, :password, :screenname)
end
end
and then I have a rspec test like this
describe "POST /users.json" do
let!(:daniel_attrs) { FactoryGirl.attributes_for(:user, username: "daniel", email: "daniel#bigbob.com", password: "999d53a384afd57ebc36986fe9455c6e941cd844467e28f975289845d6e984ee", screenname: 'Daniel', avatar: "default.png") }
before :each do |example|
post '/users.json', daniel_attrs
end
# ...
end
which fails like this
1) Users API POST /users.json creates the user with the right parameters
Failure/Error: post '/users.json', daniel_attrs
ActionController::ParameterMissing:
param is missing or the value is empty: user
# ./app/controllers/users_controller.rb:155:in `user_params'
# ./app/controllers/users_controller.rb:72:in `create'
# ./spec/requests/usersapi_spec.rb:85:in `block (3 levels) in <top (required)>'
What I'm not clear on is why would the controller even require a 'user' key in the request, since if I forge a request (via curl, postman, whatever) and I only include a json representation of my attributes, it creates the object correctly. If anyway I provide the key (as in :user => daniel_attrs) the test fails like this
1) Users API POST /users.json creates the user with the right parameters
Failure/Error: post '/users.json', :user => daniel_attrs
Apipie::ParamMissing:
Missing parameter username
# ./spec/requests/usersapi_spec.rb:85:in `block (3 levels) in <top (required)>'
and I know for a fact (because I used let! and because I printed it out) that daniel_attrs has all the keys and values at the right places.
I'm sure I'm missing something very obvious, I haven't been at rails testing for a veeery long time. So, what is it that I'm missing?
EDIT: generally, it would be massively helpful to inspect requests before they get performed. Is there any way to do this?
EDIT 2: Works when modifying the apipie definition like this
api :POST, '/users', "Creates a new user"
param :user, Hash, :required => true do
param :username, String, :required => true, :desc => "Desired username"
param :email, /[a-zA-Z0-9\-.]+\#[a-zA-Z0-9\-.]+\.[a-z]{2,}/, :required => true, :desc => "User's e-mail address"
param :password, String, :required => true, :desc => "SHA256(username:password), hex encoded"
param :screenname, String, :required => true, :desc => "Publicly visible name"
param :avatar, String, :required => true, :desc => "Uploaded avatar filename"
end
error :code => 422, :desc => "Unprocessable entity"
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.json { render :show, status: :created, location: #user }
else
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
This is because of user_params method of your controller.
I think you can try this :
def user_params
params.permit(:username, :email, :password, :screenname)
end
Edit : Sorry I missed a part of your post, so you know the problem is because of 'user' key.
If you want to keep the user key, you can try the following syntax ( I tried it and it works )
post :create, user: daniel_attrs
Hope this helps.

before_filter not being called rails?

I have a custom method outside the generic CRUD in my friendships controller called request. My problem is that I have before_filter :require_auth set to run before all methods in my FriendshipsController.
It was working fine except for the request method.
(This makes me think it has something to do with it being out of normal CRUD?)
When I call the request method now it skips the :require_auth and goes straight to the request method which is giving me errors as I define some variables in :require_auth that I need inside the request method.
Here is my FriendshipsController:
class FriendshipsController < ApplicationController
skip_before_filter :verify_authenticity_token, :only => [:create]
before_filter :require_auth
def create
#friendship = Friendship.new(user_id: params[:user_id], friend_id: params[:friend_id], status: params[:status])
if #friendship.save
render :status => 200, :json => {:message => "Friendship Created"}
else
render :status => 500, :json => { :message => "Problem creating friendship" }
end
end
def request
# friendID = params[:friend_id]
# userID = #currentuser.id
binding.pry
#userid = #currentuser.id
#friendid = params[:friend_id]
unless (#userid == #friendid || Friendship.exists?(user_id: #userid,friend_id: #friendid))
create(:user_id => userID, :friend_id => friendID, :status => 'pending')
create(:user_id => friendID, :friend_id => userID, :status => 'requested')
end
end
end
Here is my ApplicationController where I define require_auth:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
# protect_from_forgery with: :null_session
def require_auth
binding.pry
auth_token = request.headers["HTTP_AUTH_TOKEN"]
#user = User.find_by_auth_token(auth_token)
if #user.auth_token
#currentuser = #user
else
render :status => 401, :json => {:error => "Requires authorization"}
return false
end
end
end
Chris Peters was right in the comments. My problem was that rails already has request defined. I simple changed the method name to something else and it works.
Thanks.

Making Devise respond to both html and json?

I am working on an app which needs has both website and an api and I am implementing a common Devise authentication for that. To implement this requirement I am overriding Devise Registrations Controller to respond to both html and json. For json I want the controller to return the user data and I am able to implement this, but for html I want to use the original devise behavior of signing in and redirecting to root path.
The code for Registrations Controller is:
class RegistrationsController < Devise::RegistrationsController
def create
#user = User.create(user_params)
respond_to do |format|
format.html {
#user.save ? (super) : (render :new)
}
format.json {
#user.save ? (render :json => {:state => {:code => 0}, :data => #user }) :
(render :json => {:state => {:code => 1, :messages => #user.errors.full_messages} })
}
end
end
private
def user_params
params.require(:user).permit(:email, :password)
end
end
Using this controller I get a validation error Email has already been taken but when I check my logs it shows the user has been created.
Can anyone tell me what error I am doing? I just want my controller to fallback to original devise functionality in case of html request.
The problem was when you used HTML, you created the user twice by running both #user = User.create(user_params) and super. I moved that first line of code to JSON format, and HTML to only run super.
class RegistrationsController < Devise::RegistrationsController
def create
respond_to do |format|
format.html {
super
}
format.json {
#user = User.create(user_params)
#user.save ? (render :json => {:state => {:code => 0}, :data => #user }) :
(render :json => {:state => {:code => 1, :messages => #user.errors.full_messages} })
}
end
end
private
def user_params
params.require(:user).permit(:email, :password)
end
end
Here is the working version of the code (tested locally myself).
You controller should look like:
def create
#user = User.create(user_params)
respond_to do |format|
format.html {
#user.save ? (render #user) : (render 'layouts/application')
}
format.json {
#user.save ? (render :json => {:state => {:code => 0}, :data => #user }) :
(render :json => {:state => {:code => 1, :messages => #user.errors.full_messages} })
}
end
end
Add a _user partial app/views/users/_user.html.erb:
<p>
<%= #user.email %>
<%= #user.created_at %>
<%= #user.updated_at %>
</p>
So, the changes are minimal. Once you make these changes, your RegistrationsController#create action will work successfully for HTML format.

Resources