I'm building a two sided marketplace, where users are paid out when an item of theirs, sells.
I have a form that a user fills out when wanting to list an item on the marketplace. It includes many inputs, but the important ones for this question are the Stripe COUNTRY, ACCOUNT, and ROUTING inputs. This is so that they can be paid automatically after their items sells.
I'm storing a Stripe recipient ID in the user database, so that they don't have to enter their bank account info every time they post a new item. (Which can be seen in the #create action) Everything that I'm about to post below works perfectly, BUT ONLY ONCE. After posting an item the first time, the user Recipient ID successfully saves to my user database. BUT, if that user attempts to post another item, I get a Stripe error, saying that: "You must supply either a card, customer, or bank account to create a token.", when attempting to submit the form. This error is shown in my Stripe dashboard as well.
I am under the assumption that is has to do with Strong Params? At first, I did not have :Country, :Routing_number, or :Account_number in the params in the listing_controller, so I have added them in, but it did not fix the error. Am I close? Can anyone spot what I'm doing wrong?
_FORM.HTML.ERB:
<%= form_for #listing, :html => { :multipart => true } do |f| %>
<% if #listing.errors.any? %>
<div id="error_explanation" class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">× </button>
<h2><%= pluralize(#listing.errors.count, "error") %> prohibited this listing from being saved:</h2>
<ul>
<% #listing.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div id="stripe_error" class="alert alert-danger" style="display:none">
<noscript> Javascript is disabled. Order cannot be placed. First enable it in your browser.</noscript>
<% if current_user.recipient.blank? %>
<br>
<h1>Bank Account Information</h1>
<p class="sm-message">(You'll only need to enter this once.)</p>
<div class="form-group">
<%= label_tag :country %>
<%= text_field_tag :country, nil, { :name => nil, :'data-stripe' => "country", class: "form-control" } %>
</div>
<div class="form-group">
<%= label_tag :routing_number %>
<%= text_field_tag :routing_number, nil, { :name => nil, :'data-stripe' => "routingNumber", class: "form-control" } %>
</div>
<div class="form-group">
<%= label_tag :account_number %>
<%= text_field_tag :account_number, nil, { :name => nil, :'data-stripe' => "accountNumber", class: "form-control" } %>
</div>
<% end %>
<div class="form-group">
<%= f.submit class: "btn btn-primary btn-lg" %>
</div>
<% end %>
</div>
LISTING_CONTROLLER.RB
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, only: [:seller, :new, :create, :edit, :update, :destroy]
before_filter :check_user, only: [:edit, :update, :destroy]
def seller
#listings = Listing.where(user: current_user).order("created_at DESC")
end
# GET /listings
# GET /listings.json
def index
#listings = Listing.all.order("created_at DESC")
end
# GET /listings/1
# GET /listings/1.json
def show
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params)
#listing.user_id = current_user.id
if current_user.recipient.blank?
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
recipient = Stripe::Recipient.create(
:name => current_user.name,
:type => "individual",
:bank_account => token
)
current_user.recipient = recipient.id
current_user.save
end
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render :show, status: :created, location: #listing }
else
format.html { render :new }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { render :show, status: :ok, location: #listing }
else
format.html { render :edit }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url, notice: 'Listing was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:name, :description, :price, :duration, :street, :city, :state, :image, :duration, :category, :terms,
:country, :account_number, :routing_number, :stripeToken)
end
def check_user
if current_user != #listing.user
redirect_to root_url, alert: "Sorry, that is not your listing."
end
end
end
LISTING.JS.COFFEE
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
listing.setupForm()
listing =
setupForm: ->
$('#new_listing').submit ->
if $('input').length > 8
$('input[type=submit]').attr('disabled', true)
Stripe.bankAccount.createToken($('#new_listing'), listing.handleStripeResponse)
false
handleStripeResponse: (status, response) ->
if status == 200
$('#new_listing').append($('<input type="hidden" name="stripeToken" />').val(response.id))
$('#new_listing')[0].submit()
else
$('#stripe_error').text(response.error.message).show()
$('input[type=submit]').attr('disabled', false)
STRIPE DASHBOARD INFORMATION BEING RETURNED:
key: "pk_test_WgTil6dDhXN6JqzqZI4Gjw0M"
callback: "sjsonp1404518718631"
_method: "POST"
error:
type: "invalid_request_error"
message: "You must supply either a card, customer, or bank account to create a token."
The problem might be here:
current_user.recipient = recipient.id
current_user.save
You're saving an ID where an object is expected. Try:
current_user.recipient = recipient
current_user.save
Related
I'm creating a form in which I create related records, so far it works pretty well, it creates the nested records but when I create them it shows in the same form the related records created before, I just need to save records and not show the ones created in the textfields, how can I do that? this is my form
<%= form_with(model: drugs_device, local: true, html: {class: "formulario_validado"}) do |form| %>
<div class="form-row">
<div class="form-group col-md-6">
<%= form.label :abbreviation,"Código / ATC" %>
<%= form.text_field :abbreviation, class:"form-control", required: "true"%>
</div>
<%=form.fields_for :detail_drugs_devices do |fd| %>
<div class="form-row">
<div class="form-group col-md-3">
<%= fd.label :drug_concentration,"Concentration:" %>
<%= fd.text_field :drug_concentration, class:"form-control" %>
</div>
<div class="form-group col-md-3">
<%= fd.label :route_id,"Vía de administración" %>
<%= fd.select :route_id, options_for_select(#routes.map{|e|[e.description, e.id]}), {:prompt => "Por favor seleccione"}, {:class => "form-control"} %>
</div>
</div>
<%end%>
<div class="row">
<div class="col-md-4 offset-md-8 ">
<%= submit_tag "Guardar", class: "btn btn-primary"%>
</div>
</div>
</div>
<%end%>
my model drugs_device:
class DrugsDevice < ApplicationRecord
belongs_to :group
has_many :detail_drugs_devices
accepts_nested_attributes_for :detail_drugs_devices, reject_if: proc { |attributes| attributes['pharmaceutical_form_id'].blank?}
end
my model DetailDrugsDevice
class DetailDrugsDevice < ApplicationRecord
belongs_to :drugs_device
belongs_to :pharmaceutical_form
belongs_to :unit_size
belongs_to :route
end
my controller:
class DrugsDevicesController < ApplicationController
before_action :set_drugs_device, only: [:show, :edit, :update, :destroy]
# GET /drugs_devices
# GET /drugs_devices.json
def index
##drugs_devices = DrugsDevice.Busqueda_general(params).paginate(page: params[:page]).per_page(3)
#drugs_devices = DrugsDevice.all.paginate(page: params[:page]).per_page(3)
end
# GET /drugs_devices/1
# GET /drugs_devices/1.json
def show
end
# GET /drugs_devices/new
def new
#drugs_device = DrugsDevice.new
#drugs_device.detail_drugs_devices.build
#grupos = Group.all
#pharmaceutical_forms = PharmaceuticalForm.all
#unit_sizes = UnitSize.all
#routes = Route.all
end
# GET /drugs_devices/1/edit
def edit
#drugs_device.detail_drugs_devices.build
#grupos = Group.all
#pharmaceutical_forms = PharmaceuticalForm.all
#unit_sizes = UnitSize.all
#routes = Route.all
end
# POST /drugs_devices
# POST /drugs_devices.json
def create
#drugs_device = DrugsDevice.new(drugs_device_params)
respond_to do |format|
if #drugs_device.save
format.html { redirect_to edit_drugs_device_path(#drugs_device), notice: 'Drugs device was successfully created.' }
format.json { render :show, status: :created, location: #drugs_device }
else
format.html { render :new }
format.json { render json: #drugs_device.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /drugs_devices/1
# PATCH/PUT /drugs_devices/1.json
def update
respond_to do |format|
if #drugs_device.update(drugs_device_params)
format.html { redirect_to edit_drugs_device_path(#drugs_device), notice: 'Drugs device was successfully updated.' }
format.json { render :show, status: :ok, location: #drugs_device }
else
format.html { render :edit }
format.json { render json: #drugs_device.errors, status: :unprocessable_entity }
end
end
end
# DELETE /drugs_devices/1
# DELETE /drugs_devices/1.json
def destroy
#drugs_device.destroy
respond_to do |format|
format.html { redirect_to drugs_devices_url, notice: 'Drugs device was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_drugs_device
#drugs_device = DrugsDevice.find(params[:id])
end
# Only allow a list of trusted parameters through.
def drugs_device_params
params.require(:drugs_device).permit(:group_id, :atc, :abbreviation, :cientific_name, :stated_at, detail_drugs_devices_attributes: [:pharmaceutical_form_id, :unit_size_id, :route_id, :drug_concentration, :id])
end
end
I have a Ruby on Rails app that handles a users income, decides if it is an allowance or an income and applies the appropriate tax rates. I have included some enums to do basic functions as outlined below.
When I go to update from the default I hit the issue '1' is not a valid incomeType.
Below you can see the set up including model, controller and form.
model :
class Income < ApplicationRecord
enum incomeType: {income: 0, allowance: 1 }
enum taxed: {yes: 0, no: 1 }
belongs_to :user
end
controller:
class IncomesController < ApplicationController
before_action :set_income, only: [:show, :edit, :update, :destroy]
# GET /incomes
# GET /incomes.json
def index
#incomes = current_user.incomes.all
end
# GET /incomes/1
# GET /incomes/1.json
def show
end
# GET /incomes/new
def new
#income = current_user.incomes.build
end
# GET /incomes/1/edit
def edit
end
# POST /incomes
# POST /incomes.json
def create
#income = current_user.incomes.new(income_params)
respond_to do |format|
if #income.save
format.html { redirect_to #income, notice: 'Income was successfully created.' }
format.json { render :show, status: :created, location: #income }
else
format.html { render :new }
format.json { render json: #income.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /incomes/1
# PATCH/PUT /incomes/1.json
def update
respond_to do |format|
if #income.update(income_params)
format.html { redirect_to #income, notice: 'Income was successfully updated.' }
format.json { render :show, status: :ok, location: #income }
else
format.html { render :edit }
format.json { render json: #income.errors, status: :unprocessable_entity }
end
end
end
# DELETE /incomes/1
# DELETE /incomes/1.json
def destroy
#income.destroy
respond_to do |format|
format.html { redirect_to incomes_url, notice: 'Income was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_income
#income = Income.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def income_params
params.require(:income).permit(:amount, :frequency, :user_id, :incomeType, :country, :taxed)
end
end
Form :
<%= form_with(model: income, local: true) do |form| %>
<% if income.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(income.errors.count, "error") %> prohibited this income from being saved:</h2>
<ul>
<% income.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :amount %>
<%= form.text_field :amount, id: :income_amount %>
</div>
<div class="field">
<%= form.label :frequency %>
<%= form.select :frequency, options_for_select([['Weekly', '52'], ['Fortnightly', '26'], ['Monthly', '12'], ['Bi-Monthly', '6'], ['Annually', '1']]), id: :income_frequency %>
</div>
<div class="field">
<%= form.label :incomeType %>
<%= form.select :incomeType, options_for_select([['Income', '0'], ['Allowance', '1']]), id: :incomeType %>
</div>
<div class="field">
<%= form.label :taxed %>
<%= form.select :taxed, options_for_select([['Yes', '0'], ['No', '1']]), id: :taxed %>ra
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Hopefully you can point me in the right direct.
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"HUTd5Bav9eAfWPTFFyqeD69aL4mIgZodIuL1+9eL0zIhN+SjDwAMcD7AzKEuhm6az4iALBSrDUXd/1vVfN77SQ==",
"income"=>{"amount"=>"102000.0", "frequency"=>"1", "incomeType"=>"0", "taxed"=>"1"},
"commit"=>"Update Income",
"id"=>"4f9fc439-4578-487e-bc5d-02cf0cd9aaa3"}
Thanks in advance for your help
Yes it is because enum needs key not the value and you are sending value not the key so in your case enum is trying to find '0' as one key which is not present. So just change your form slightly
<%= form.select :incomeType, options_for_select([['Income', 'income'], ['Allowance', 'allowance']]), id: :incomeType %>
PS : change form for taxed as well.
Hope this will help
I am using Paperclip to upload an image and display in a pin. But it display a missing image and the pin stores null value for image properties. I have gone through different post here but still unable to fix it.
<Pin id: 7, description: "Hello", created_at: "2016-08-14 20:13:10", updated_at: "2016-08-14 20:13:10",user_id: 2, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil>
pin model
class Pin < ActiveRecord::Base
belongs_to :user
has_attached_file :image
validates_attachment :image, content_type: { content_type: ["image/jpg",
"image/jpeg", "image/png", "image/gif"] }
end
pins controller
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#pins = Pin.all
end
def show
end
def new
#pin = current_user.pins.build
end
def edit
end
def create
#pin = current_user.pins.build(pin_params )
respond_to do |format|
if #pin.save
format.html { redirect_to #pin, notice: 'Pin was successfully created.' }
format.json { render :show, status: :created, location: #pin }
else
format.html { render :new }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #pin.update(pin_params)
format.html { redirect_to #pin, notice: 'Pin was successfully updated.' }
format.json { render :show, status: :ok, location: #pin }
else
format.html { render :edit }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
def destroy
#pin.destroy
respond_to do |format|
format.html { redirect_to pins_url, notice: 'Pin was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Unauthorized to edit" if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image)
end
end
View
<%= form_for #pin, html: {multipart: true} do |f| %>
<% if #pin.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#pin.errors.count, "error") %> prohibited this pin from being saved:</h2>
<ul>
<% #pin.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="col-sm-8">
<div class="form-horizontal">
<div class="form-group">
<div class="field">
<%= f.label :image , class: "col-sm-3 control-label" %>
<div class="col-sm-5"><%= f.file_field :image , class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class="field">
<%= f.label :description , class: "col-sm-3 control-label" %>
<div class="col-sm-5"><%= f.text_field :description , class: "form-control" %>
</div>
</div>
</div>
<div class="form-group">
<div class="actions">
<div class="col-sm-3"></div>
<div class="col-sm-5">
<%= f.submit class: "btn btn-danger" %>
</div>
</div>
</div>
</div>
I am trying to improve an exercice that I did on treehouse, the idea was to remake a little version of facebook thing, where users could publish statuses.
Now I want that a user can comment any statuses... And I am kinda lost...
The idea is to have all on the same page (if possible?, like on the real facebook)
So the comment form and the "displaying" content...
I hope anyone could help me :)
This is my github repository
I think I haven't understand how to call variables from a controller to another...
If someone could explain me with very easy words ... I am not native english speaker... so sometime it's difficult..
Here are the statuses part
controllers/statuses_controller/rb
class StatusesController < ApplicationController
before_filter :authenticate_user!, only: [:new, :create, :edit, :update]
before_action :set_status, only: [:show, :edit, :update, :destroy]
def index
#statuses = Status.all
#comments = Comment.all
end
def show
#status = Status.find(params[:id])
#comments = #status.comments.all
end
def new
#status = Status.new
#comment = #status.comments.build
end
def create
#status = Status.new(status_params)
#status.user = current_user
respond_to do |format|
if #status.save
format.html { redirect_to #status, notice: 'Status was successfully created.' }
format.json { render :show, status: :created, location: #status }
else
format.html { render :new }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #status.update(status_params)
format.html { redirect_to #status, notice: 'Status was successfully updated.' }
format.json { render :show, status: :ok, location: #status }
else
format.html { render :edit }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
def destroy
#status.destroy
respond_to do |format|
format.html { redirect_to statuses_url, notice: 'Status was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_status
#status = Status.find(params[:id])
end
def status_params
params.require(:status).permit(:user_id, :content, :comments_attribute[:id, :status_id, :content])
end
end
models/status.rb
class Status < ActiveRecord::Base
belongs_to :user
has_many :comments
default_scope -> { order(created_at: :DESC)}
validates :content, presence: true,
length: {minimum: 2}
validates :user_id, presence: true
end
views/comments/_form.html.erb I create a render in my index below:
<% simple_form_for #status.comments do |f|%>
<%= f.input :content %>
<%= f.button :submit %>
<% end %>
view/statuses/index.html.erb
<div class="page-header">
<h1>All of the Statuses</h1>
</div>
<%= link_to "Post A New Status", new_status_path, class: "btn btn-success"%>
<br>
<br>
<% #statuses.each do |status| %>
<div class="status">
<div class="row">
<div class="col-xs-1 avatar">
<%= image_tag status.user.avatar.thumb if status.user.avatar?%>
</div>
<div class="col-xs-7">
<h4><%= status.user.full_name%></h4>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<p><%= simple_format(status.content) %></p>
</div>
</div>
<div class="row">
<div class="col-xs-8">
<%= link_to time_ago_in_words(status.created_at) + " ago", status %>
<% if status.user == current_user %>
<span class="admin">
| <%= link_to "Edit", edit_status_path(status) %> |
<%= link_to "Delete", status, method: :delete, data: {confirm: "Are you sure?"} %>
</span>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<p>Comments</p>
<% #comments.each do |comment| %>
<%= comment.content %>
<% end %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<%= render "comments/form" %>
</div>
</div>
</div>
Now the comments part:
model/comment.rb
class Comment < ActiveRecord::Base
belongs_to :status
belongs_to :user
end
controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(params_comment)
end
def index
#statuses = Status.all
#comments = Comment.all
#comment = Comment.find_by(params[:id])
end
private
def params_comment
params.require(:comment).permit(:content)
end
end
routes.rb
resources :statuses do
resources :comments
end
user.rb
that's a part of what I have in there
has_many :statuses
has_many :comments
your comments creation method should look like this:
#status = Status.find(params[:status_id])
#comment = #status.comments.create(comment_params)
#comment.user_id = current_user.id if current_user
#comment.save
having installed the latest version of paperclip , i get an error every time i try and upload an image , i can click on the upload button , select my image but when i try to create a listing/image i get error Paperclip::Errors::MissingRequiredValidatorError in ListingsController#create Paperclip::Errors::MissingRequiredValidatorError ..imagemagick installed as well
listings.controller.rb
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
# GET /listings
# GET /listings.json
def index
#listings = Listing.all
end
# GET /listings/1
# GET /listings/1.json
def show
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params) **<------ERROR**
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render action: 'show', status: :created, location: #listing }
else
format.html { render action: 'new' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:name, :description, :price, :image)
end
end
listing.rb
class Listing < ActiveRecord::Base
has_attached_file :image, :styles => { :medium => "200x", :thumb => "100x100>" }, :default_url => "missing.jpg"
end
_form.html.erb
<%= form_for(#listing, :html => { :multipart => true }) do |f| %>
<% if #listing.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#listing.errors.count, "error") %> prohibited this listing from being saved:</h2>
<ul>
<% #listing.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description %>
<%= f.text_area :description, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :price %>
<%= f.text_field :price, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit class: "btn btn-primary" %>
</div>
<% end %>
You have to add a validation of content type in your model:
validates_attachment_content_type :image, content_type: %w(image/jpeg image/jpg image/png)