I have a rails 4.1 app that is using Balanced to process credit cards. The credit card form I have is using ajax to post to the backend but I am getting the following error:
ActionController::ParameterMissing - param is missing or the value is empty
actionpack (4.1.4) lib/action_controller/metal/strong_parameters.rb:183:in `require'
here is my controller:
class TablechargesController < ApplicationController
def new
#event = Event.find(params[:event_id])
#table = #event.tablecharges.build
end
def index
#event = Event.find(params[:event_id])
#table = #event.tablecharges.all
end
def create
#event = Event.find(params[:event_id])
#table = #event.tablecharges.build(table_charge_params)
if #table.save
redirect_to #event, :notice => "Thanks for the cash"
else
render :new
end
end
private
def table_charge_params
params.require(:tablecharge).permit(:uri, event_attributes: :id)
end
end
here is my model:
class Tablecharge < ActiveRecord::Base
belongs_to :event
attr_accessor :cc_name
attr_accessor :cc_number
attr_accessor :cc_expiration_month
attr_accessor :cc_expiration_year
attr_accessor :cc_ccv
attr_accessor :uri
end
here is my Javascript:
jQuery ->
$('#cc-submit').click (e) ->
e.preventDefault()
handleResponse = (response) ->
if (response.status_code == 201)
fundingInstrument = (if response.cards? then response.cards[0] else response.bank_accounts[0])
alert(fundingInstrument.href)
$('#tablecharge_uri').val(fundingInstrument.href)
url = '/events/' + urlid + '/tablecharges'
alert(url)
jQuery.ajax({type: "POST", url: url, data: {uri: fundingInstrument.href, event_id: urlid}, sucess: (data) ->
alert data.id
error: (data) ->
alert "fuck"})
else
alert(response.status + JSON.stringify(response, false, 1))
payload = {
name: $('#cc-name').val()
number: $('#cc-number').val()
expiration_month: $('#cc-expiration-month').val()
expiration_year: $('#cc-expiration-year').val()
ccv: $('#cc-ccv').val()
}
balanced.card.create(payload, handleResponse)
here is my view:
<div class="authform">
<%= javascript_tag do %>
window.urlid = "<%= #table.event_id %>"
<% end %>
<%= simple_form_for [#event, #table] do |f| %>
<%= f.input :cc_name, input_html: {id: 'cc-name'}%>
<%= f.input :cc_number, input_html: {id: 'cc-number'} %>
<%= f.input :cc_expiration_month, as: :integer, input_html: {id: 'cc-expiration-month'} %>
<%= f.input :cc_expiration_year, as: :integer, input_html: {id: 'cc-expiration-year'} %>
<%= f.input :cc_ccv, input_html: {id: 'cc-ccv'} %>
<%= f.input :uri, as: :hidden %>
<%= f.button :submit, id: 'cc-submit', remote: true %>
<% end %>
The first value in your data object has to be :tablecharge as you specified that all the params belong to that object.
So the data you are passing in your ajax request should be formatted like this:
data: { tablecharge: {uri: fundingInstrument.href, event_id: urlid}}
Related
I've got an app where the user has to fill out a survey. I need to store user's answers in inside TestResult model which have only one field answers:string
With current implementation I'm getting params from the form as:
params => {
{
"question_#{id}": "some answer 1",
"question_#{id}": "some answer 12345",
}
}
Which I want to change to the below structure:
# expected hash params
params => {
{
question: 'first question',
answer: 'some answer 1'
},
{
question: 'second question',
answer: 'some answer 123431'
}
}
What should I change (probably in a view) to get this hash?
new.html.erb
<%= simple_form_for :test_results, url: test_results_path do |f| %>
<% #randomize_questions.map do |q| %>
<%= q[:question] %>
<%= f.input "question_#{q[:id]}", collection: q[:answers], as: :radio_buttons %>
<% end %>
<%= f.button :submit %>
<% end %>
controller:
class TestResultsController < ApplicationController
before_action :fetch_random_questions, only: [:new, :create]
def new
#test_result = TestResult.new
end
def create
#test_result = TestResult.new(
answer: test_result_params,
)
#test_result.save
redirect_to dummy_path
end
end
private
def test_result_params
params.require(:test_results).permit!
end
def fetch_random_questions
TestQuestion.where(published: true).order('RANDOM()')
#randomize_questions = test_questions.map do |obj|
{
id: obj.id,
question: obj.question,
answers: [obj.correct_answer, obj.other_answer1, obj.other_answer2, obj.other_answer3],
}
end
end
end
TestResult model
class TestResult < ApplicationRecord
serialize :answer, Hash
serialize :answer, String
validates :answer, presence: true
end
The params get his structure from the input names.
So you could add an hidden field for question, and then specify a name for both of your fields.
<%= simple_form_for :test_results, url: test_results_path do |f| %>
<% #randomize_questions.map do |q| %>
<%= q[:question] %>
<%= f.input "question_#{q[:id]}", as: :hidden, input_html: { name: "test_results[#{q[:id]}][question]", value: q[:question] } %>
<%= f.input "question_#{q[:id]}", collection: q[:answers], as: :radio_buttons, input_html: { name: "test_results[#{q[:id]}][answer]" } %>
<% end %>
<%= f.button :submit %>
<% end %>
Params should looks like this:
params => {
test_result: {
1 => {
question: "...",
answer: "..."
},
2 => {
question: "...",
answer: "..."
}
}
}
Not tested. Could you tell if that's works for you?
I am trying to create a form that updates 2 tables - commission_type and commission_tier.
I created the models, controller and form but when I submit it, my commission_tier table does not update. Only my commission_type table updates.
Can someone take a look at my code and tell me what I am doing wrong? I have combed through my code trying to find the mistake, and I cannot find it.
My models
class CommissionType < ApplicationRecord
has_many :commission_tiers
accepts_nested_attributes_for :commission_tiers
end
class CommissionTier < ApplicationRecord
belongs_to :commission_types, optional: true
end
My controller
class Admin::CommissionTypesController < Admin::BaseController
def index
#commission_types = CommissionType.all
end
def new
#commission_type = CommissionType.new
#commission_type.commission_tiers.build
end
def create
#commission_type = CommissionType.new(commission_type_params)
if #commission_type.save
redirect_to admin_commission_types_index_path
else
render "new"
end
private
def commission_type_params
params.require(:commission_type).permit(:name, :active, :allow_mass_update, :plan,
commission_tiers_attributes: [:id, :increment_value, :rate, :commission_type_id])
end
end
My form
<%= simple_form_for #commission_type, url: admin_commission_types_index_path, wrapper: :bootstrap2, :html => { :class => 'form-horizontal' } do |f| %>
<fieldset>
<legend>Properties</legend>
<%= f.input :name, label: 'Commission Name' %>
<%= f.input :active, as: :boolean, label: 'Active?', label_html: { class: 'padding-top' } %>
<%= f.input :allow_mass_update, as: :boolean, label: 'Allow mass update?', label_html: { class: 'padding-top' } %>
<%= f.input :plan, input_html: {id: 'dropdown'},
label: 'Commission Type',
collection: [ ['Select One..', 'select'], ['Flat', 'flat'], ['Flat +', 'flat_plus' ], ['Promotional', 'promotional'], ['Straight', 'straight'], ['Waterfall', 'waterfall'], ['Sliding Scale', 'sliding_scale'] ],
selected: 'select'
%>
</fieldset>
<fieldset id="flat">
<legend>Flat Commission</legend>
<%= f.simple_fields_for :commission_tiers do |builder| %>
<%= builder.input :rate %>
<%= builder.input :increment_value %>
<% end %>
</fieldset>
My form is displaying and working
UPDATE
Some additional details
CommissionType column values = [:name, :active, :allow_mass_update, :plan]
CommissionTier column values = [:id, :increment_value, :rate, :commission_type_id]
Also, when I submit my form, here is an example of what my params are
<ActionController::Parameters {"name"=>"asdf", "active"=>"1", "allow_mass_update"=>"1", "plan"=>"flat", "commission_tiers_attributes"=><ActionController::Parameters {"0"=><ActionController::Parameters {"rate"=>"45"} permitted: true>} permitted: true>} permitted: true>
I am working on a project where we have to filter event based on location, date, sport, and skill level. At the moment each filter works individually but I I cannot chain them to get even more specific results.
This is what I have in my model.
include PgSearch::Model
pg_search_scope :global_search,
against: [:location, :sport, :level, :date]
pg_search_scope :date_search,
against: [:date]
pg_search_scope :sport_search,
against: [:sport],
using: {
tsearch: { prefix: true }
}
pg_search_scope :location_search,
against: [:location],
using: {
tsearch: { prefix: true }
}
pg_search_scope :level_search,
against: [:level]
enum level: { Beginner: 1, Intermediate: 2, Advanced: 3, Pro: 4 }
And this is in my controller.
def index
if params[:search][:location].present?
#events = policy_scope(Event).location_search(params[:search][:location])
elsif params[:search][:sport].present?
#events = policy_scope(Event).sport_search(params[:search][:sport])
elsif params[:search][:date].present?
#events = policy_scope(Event).date_search(params[:search][:date])
elsif params[:search][:level].present?
#events = policy_scope(Event).level_search(params[:search][:level])
else
#events = policy_scope(Event)
end
#markers = #events.geocoded.map do |event|
{
lat: event.latitude,
lng: event.longitude
}
end
end
And these are my filters
<div id="collapseFilters" class="container collapse form">
<%= simple_form_for :search, url: events_path, method: "GET", html: { class: 'form-block' } do |f| %>
<%= f.input :date, as: :string, required: false, input_html: {class: "datepicker"} %>
<%= f.input :level, collection: Event.levels.map{ |l| [l.first, l.second] }, required: false, label_method: :first, value_method: :second%>
<%= f.input :location, required: false, placeholder: 'Enter a location for your event' %>
<%= f.button :submit, 'Search', class: "btn btn-primary btn-lg btn-form mt-3" %>
<% end %>
</div>
How could I chain them in the params so I could use more than one filter at once?
You can update your controller:
def index
#events = policy_scope(Event)
#events = #events.location_search(params[:search][:location]) if params[:search][:location].present?
#events = #events.sport_search(params[:search][:sport]) if params[:search][:sport].present?
#events = #events.date_search(params[:search][:date]) if params[:search][:date].present?
#events = #events.level_search(params[:search][:level]) if params[:search][:level].present?
#markers # ...
end
or even (if it is clear enough for you)
def index
#events = policy_scope(Event)
%i[location sport date level].each do |filter|
next unless params[:search][filter].present?
#events = #events.public_send("#{filter}_search", params[:search][filter])
end
#markers # ...
end
if I get how this gem works right.
You should use multisearchable option as described in documentation https://github.com/Casecommons/pg_search
There is the following form code:
= form_for #task, html: { class: 'form-horizontal' } do |f|
.form-group
.col-sm-9.col-sm-offset-3
= render partial: 'shared/form_errors', locals: { subject: #task }
.form-group
label.col-sm-3.control-label for='title' Title
.col-sm-9
= f.text_field :title, class: 'form-control', placeholder: 'Title'
.form-group
label.col-sm-3.control-label for='description' Description
.col-sm-9
= f.text_area :description, class: 'form-control', placeholder: 'Description'
.form-group
label.col-sm-3.control-label Teams
.col-sm-9
ul
- Team.all.each do |t|
li
= check_box_tag "team_ids", t.id, #task.teams.include?(t), name: 'task[team_ids][]'
= t.name
.form-group
.col-sm-9.col-sm-offset-3
= f.submit 'Save', class: 'btn btn-success'
As you can see I can select team for my task through checkboxes. My controller:
def update
#task = Task.find(params[:id])
if #task.update(task_params)
redirect_to tasks_path, flash: { alert: TASK_UPDATING_MESSAGE }
else
render 'edit'
end
end
private
def task_params
params.require(:task).permit(:title, :description, team_ids: [])
end
It works good if I update task with some checked teams; but also I want to have ability to check no teams and update taks with empty array of teams. But in this case tasks_params doesn't have team_ids array, and updating doesn't work. How can I fix it? Thanks!
My understanding is that when you submit your form with nothing checked, you have params[:task][:team_ids] = nil.
You can try something like:
def task_params
params[:task][:team_ids] = [] if params[:task][:team_ids].nil?
params.require(:task).permit(:title, :description, team_ids: [])
end
You can do it using collection_check_boxes, just replace the list of teams with:
ul
= f.collection_check_boxes :team_ids ,Team.all, :id, :name do |b|
= content_tag :li, raw("#{b.label { b.check_box } }" + b.object.name)
And this will do the trick.
Note: With this Rails add a hidden field, which fix your issue, also you will fix it only with this:
<input type="hidden" name="task[team_ids][]" value="" autocomplete="off">
In my Rails application I have simple search functionality. I want to extract to Form Object but don't know how to do. I have search form which looks like this:
.row
= horizontal_simple_form_for :cars, {url: cars_path, method: :get} do |f|
.col-md-4
.row
.col-md-12
= f.input :handover_location, label: I18n.t('.handover'), collection: Location.all.map{|hl| [hl.location_address, hl.id]}
= f.input :return_location, label: I18n.t('.return') ,collection: Location.all.map{|rl| [rl.location_address, rl.id]}
= f.input :car_class, label: I18n.t('.car_class') ,collection: CarClass.all.map { |c| [c.name, c.id] }, include_blank: true
.col-md-4
= f.input :handover_date, as: :string, label: false
= f.input :return_date, as: :string, label: false
= f.submit class: 'btn btn-success'
Cars controller:
class CarsController < ApplicationController
skip_authorization_check
def index
#cars = Car.search(params)
end
def show
end
end
And class method in Car model which search correct cars:
def self.search(params)
self.joins(:reservations).where.not("reservations.reception_time <= ? AND reservations.return_time >= ?",
params[:cars][:return_date], params[:cars][:handover_date]).
joins(:car_class).where("car_classes.id= ?", params[:cars][:car_class])
.cars_at_both_locations(params[:cars][:handover_location], params[:cars][:return_location])
end
Now I'm trying to extract this to Form Object. I've created a file search_form.rb:
class SearchForm
include ActiveModel::Model
attr_accessor :handover_date, :return_date, :handover_location, :return_location, :car_class
end
But now I don't know how to handle my params to this form object. Thank's in advance.
I wish I could help you with the Form Object stuff, but I need to learn more about classes & modules
I can help you with the search functionality, as we've done it before here
Here's the code we used:
#View
<%= form_tag search_path, :method => :post, :id => "SearchForm" do %>
<%= text_field_tag :search, params[:search], placeholder: 'Search your favourite products or brands', :autocomplete => :off %>
<%= image_submit_tag 'nav_bar/search.png' %>
<% end %>
#config/routes.rb
match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]
#app/controllers/products_controller.rb
def search
#products = Product.search(params[:search])
respond_to do |format|
format.js { render :partial => "elements/livesearch", :locals => {:search => #products, :query => params[:search]} }
format.html { render :index }
end
end
Notice the form_tag we used?
Simple form does not work with form_tag currently (it requires an object) - we just send the data with a GET request to the controller & that then sends the data to the Product model
I think your problem will be caused by the use of your SearchForm object. You only need this because your use of simple form means you have to pass an object. Problem being this is not necessary for search
A better way will be to use a standard form_tag, and send the request directly to your controller. This will allow you to process the data as params, which you'll be able to send directly to your Car model
--
I can write some code specific to you if you want
I found solution on my own.
Cars controller:
def index
#search_form = SearchForm.new(params[:search_form])
#cars = #search_form.submit(params[:search_form])
end
search_form.rb:
class SearchForm
include ActiveModel::Model
attr_accessor :handover_date, :return_date, :handover_location, :return_location, :car_class
def submit(params)
Car.search(params)
end
end
Search form in view:
.row
= horizontal_simple_form_for SearchForm.new, {url: cars_path, method: :get} do |f|
.col-md-4
.row
.col-md-12
= f.input :handover_location, label: I18n.t('.handover'), collection: Location.all.map{|hl| [hl.name, hl.id]}
= f.input :return_location, label: I18n.t('.return') ,collection: Location.all.map{|rl| [rl.name, rl.id]}
= f.input :car_class, label: I18n.t('.car_class') ,collection: CarClass.all.map { |c| [c.name, c.id] }, include_blank: true
.col-md-4
= f.input :handover_date, as: :string, label: false
= f.input :return_date, as: :string, label: false
= f.submit class: 'btn btn-success'
search method in car model:
def self.search(params)
self.joins(:reservations).where.not("reservations.reception_time <= ? AND reservations.return_time >= ?",
params[:return_date], params[:handover_date]).
joins(:car_class).where("car_classes.id= ?", params[:car_class])
.cars_at_both_locations(params[:handover_location], params[:return_location])
end