Bootstrap 3 Datetimepicker with Rails form_for - ruby-on-rails

I am a new Rails developer and I am having trouble using the bootstrap3 datetimepicker together with my rails form_for to save to a DateTime attribute in my ScheduledAccess Model. The one I am using is from http://eonasdan.github.io/bootstrap-datetimepicker/
Code:
.form-group
= f.label :start_time
datetimepicker1.input-group.date
= f.text_field :start_time, class:"form-control", id:"scheduled_access_start_time"
span.input-group-addon
span.glyphicon.glyphicon-calendar
.form-group
= f.label :end_time
datetimepicker2.input-group.date
= f.text_field :start_time, class:"form-control", id:"scheduled_access_start_time"
span.input-group-addon
span.glyphicon.glyphicon-calendar
javascript:
$(function () {
$('#datetimepicker1').datetimepicker(
{
sideBySide: true
});
$('#datetimepicker2').datetimepicker(
{
sideBySide: true
});
});
_fields.html.slim
Do note that I am able to save to my ScheduledAccess model when I use the default Rails/HTML5 datetime as shown below.
Code:
.form-group
= f.label :start_time
= f.datetime_local_field :start_time, class: "form-control"
.form-group
= f.label :end_time
= f.datetime_local_field :end_time, class: "form-control"
The following code shows how I code my ScheduledAccess controller which might be needed.
Code:
class ScheduledAccessesController < ApplicationController
before_filter :authenticate_user!
def create
#access = ScheduledAccess.new(scheduledaccess_params)
#access.user_id = current_user.id
# generate 5-digit random pin
randompin = rand(10**5)
#access.pin = randompin
if #access.save
redirect_to home_path
else
flash[:alert] = "There was some unexpected error! Please Retry!"
redirect_to new_scheduled_access_path
end
end
def destroy
end
def edit
#access = current_access
end
def new
#access = ScheduledAccess.new
end
private
def scheduledaccess_params
params.require(:scheduled_access).permit(:name,:pin, :phoneno, :start_time, :end_time, :remarks)
end
def current_access
ScheduledAccess.find(params[:id])
end
end
scheduled_accesses_controller.rb
When I use the bootstrap3 datetimepicker and try to save. I always get the flash messsage.
Any help would be appreciated! =)

Related

Rails checkbox checked updates shipping address while using form object pattern

So I have a form that I'm trying to allow the user to copy over text from billing to shipping address. Unfortunately at the moment it's automatically saving billing address in the shipping address.
My form looks like the following (albeit truncated for massive amount of fields):
=form_for #customer, url: create_customer_path, html: {class: 'new-customer} do |f|
.row
.col-md-4
= f.label :first_name
.col-md-8
= f.text_field :first_name, class: 'form-control', required:true
.row
.col-md-4
= f.label :billing_address1
.col-md-8
= f.text_field :billing_address1, class: 'form-control', required:true
.row
.col-md-12
= f.check_box :shipping_is_billing
= f.label :shipping_is_billing, 'Same as billing address'
.row
.col-md-4
= f.label :shipping_address1
.col-md-8
= f.text_field :shipping_address1
CustomersController
class CustomersController < ApplicationController
def new
#customer = CustomerForm.new
end
def create
#customer = CustomerForm.new(customer_params)
if #customer.save
redirect_to customer_success_path
else
render 'new'
end
end
private
def customer_params
params.require(:customer_form).permit!.tap do |p|
p[:captcha_response] = params['g-recaptcha-response']
end
end
end
CustomerForm (truncated for massive fields)
class CustomerForm
include ActiveModel::Model
CUSTOMER_ATTRS = %w[
first_name
].freeze
ADDRESS_ATTRS = %w[
address1 address2 city state zip
].freeze
attr_accessor(*CUSTOMER_ATTRS)
attr_accessor(*ADDRESS_ATTRS.map { |attr| 'billing_' + attr })
attr_accessor(*ADDRESS_ATTRS.map { |attr| 'shipping_' + attr })
attr_accessor :confirm_email, :captcha_response, :shipping_is_billing
validates :first_name, presence: true
validates :billing_address1, presence: true
validates :shipping_address1, presence: true, unless: :shipping_is_billing
def save
return false unless valid?
persist!
end
private
def captcha_passes
captcha = Captcha.new
return if captcha.valid?(captcha_response)
errors.add(:captcha_response, 'is invalid')
end
def persist!
customer = Customer.new(attrs_for_customer)
customer.billing_address = CustomerAddress.new(attrs_for_address('billing_'))
customer.shipping_address = CustomerAddress.new(
attrs_for_address(shipping_is_billing ? 'billing_' : 'shipping_')
)
customer.save!
customer
end
def attrs_for_customer
Hash[
CUSTOMER_ATTRS.map { |attr| [attr, send(attr)] }
]
end
def attrs_for_address(prefix)
Hash[
ADDRESS_ATTRS.map { |attr| [attr, send(prefix + attr.to_s)] }
]
end
end
JS
app.newCustomer = () => {
function init() {
let check = document.querySelector('#customer_form_shipping_is_billing')
check.addEventListener('change', toggledUseBilling)
}
let toggledUseBilling = event => {
shippingFields().forEach(field => {
if(event.target.checked) {
field.value = null;
field.removeAttribute('required');
field.setAttribute('disabled', true);
} else {
field.setAttribute('required', true);
field.removeAttribute('disabled');
}
})
}
let shippingFields = () => {
let selectors = [
'#customer_form_shipping_address1',
'#customer_form_shipping_address2',
'#customer_form_shipping_city',
'#customer_form_shipping_state',
'#customer_form_shipping_zip',
]
return document.querySelectorAll(selectors.join(', '));
}
return init();
}
Under the persist! method I'm using the ternary operator on the checkbox to determine the attributes for the address to be billing/shipping. But it doesn't look like it's actually working. How do I grab from the form the checkbox being marked?
Here are the things I've tried:
Switched = f.check_box :shipping_is_billing to =check_box_tag :shipping_is_billing. Then I had to update my JS to make sure I was grabbing the right checkbox. This stores the shipping data but when checked the business data isn't being copied.
Attempted to switch attrs_for_address(shipping_is_billing ? 'billing_' : 'shipping_') to attrs_for_address(shipping_is_billing ? 'shipping_' : 'billing_'). If I use the check_box this will populate the data over to shipping but the checkbox becomes ineffectual.
Put a form_tag around the check_box_tag but this actually stripped out the check box
Changed the check_box to check_box_tag, updated my JS to look for the correct ID on the checkbox. Can save the shipping address if typed in but if checking the box it does not apply the billing address and I get prompts that the shipping address can't be blank
Did a binding.pry within the persist! method. Looks like shipping_is_billing is pulling a string which is hitting truthy. Changed to
customer.shipping_address = CustomerAddress.new(
attrs_for_address(shipping_is_billing == "1" ? 'billing_' : 'shipping_')

NoMethodError undefined method `id' for nil:NilClass:

I know this kind of question is already answered multiple times but i seriously unable to figure it out what is causing a problem here, I am having trouble solving this problem. I keep getting the same error when i'm trying to create new registration ( http://localhost:3000/registrations/new?course_id=1 ) :
NoMethodError at /registrations
undefined method `id' for nil:NilClass
Here is my RegistrationsController:
class RegistrationsController < ApplicationController
before_action :set_registration, only: [:show, :edit, :update, :destroy]
def index
#registrations = Registration.all
end
def show
end
def new
#registration = Registration.new
#course = Course.new
#course = Course.find_by id: params["course_id"]
end
def create
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
render :new
end
protect_from_forgery except: :webhook
def webhook
event = Stripe::Event.retrieve(params["id"])
case event.type
when "invoice.payment_succeeded" #renew subscription
Registration.find_by_customer_id(event.data.object.customer).renew
end
render status: :ok, json: "success"
end
private
def stripe_params
params.permit :stripeEmail, :stripeToken
end
def set_registration
#registration = Registration.find(params[:id])
end
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token)
end
end
My Registration Model:
class Registration < ActiveRecord::Base
belongs_to :course
def process_payment
customer_data = {email: email, card: card_token}.merge((course.plan.blank?)? {}: {plan: course.plan})
customer = Stripe::Customer.create customer_data
Stripe::Charge.create customer: customer.id,
amount: course.price * 100,
description: course.name,
currency: 'usd'
#Annotate Customer Id when Registration is Created
cusotmer_id = customer.id
end
def renew
update_attibute :end_date, Date.today + 1.month
end
end
Registration New.html.haml File :
%section#course-content
%section#ruby
%section.detailed-syllabus
.wrapper-inside
= form_for #registration, html: { class: "basic-grey" } do |f|
- if #registration.errors.any?
#error_explanation
%h2
= pluralize(#registration.errors.count, "error")
prohibited this registration from being saved:
%ul
- #registration.errors.full_messages.each do |message|
%li= message
.field
= f.hidden_field :course_id, value: #course.id
.field
= f.label :full_name
= f.text_field :full_name
.field
= f.label :company
= f.text_field :company
.field
= f.label :email
= f.text_field :email
.field
= f.label :telephone
= f.text_field :telephone
//‘Stripe.js’ will recognize the card data because we have marked the inputs with ‘data-stripe’ attribute as: number, cvv, exp-month and exp-year.
= javascript_include_tag "https://js.stripe.com/v2/"
:javascript
Stripe.setPublishableKey('#{Rails.application.secrets.stripe_publishable_key}');
= label_tag "Card Number", nil, required: true
.control-group
.controls
= text_field_tag :card_number, nil, class: "input-block-level", "data-stripe" => "number"
= label_tag "Card Verification", nil, required: true
.control-group
.controls
= text_field_tag :card_verification, nil, class: "input-block-level", "data-stripe" => "cvv"
= label_tag "Card Expires", nil, required: true
= select_tag :exp_month, options_for_select(Date::MONTHNAMES.compact.each_with_index.map { |name,i| ["#{i+1} - #{name}", i+1] }), include_blank: false, "data-stripe" => "exp-month", class: "span2"
= select_tag :exp_year, options_for_select((Date.today.year..(Date.today.year+10)).to_a), include_blank: false, "data-stripe" => "exp-year", class: "span1"
.actions
= f.submit "Registration Payment", class: "btn", style: "color: white;background: rgb(242, 118, 73);"
Does anyone know how to assist me in this? Greatly appreciate all the help.
Additional Can anyone please guide me through how to pass id between 2 models like this guy did between 2 models as he's creating a scaffold for one model but passing ID lets him create values for another model too without creating actions for another controller https://github.com/gotealeaf/stripe-basics.git
Edited:
GitHub Repository For This Code
https://github.com/ChiragArya/Stripe_CheckOut_Demo
From your comments, it appears the error is caused by :
#course.id being nil
The way to fix this is to ensure #course is defined properly. You need to do the following:
def new
#registration = Registration.new
#course = Course.find_by id: params["course_id"]
end
The other issue you have here is that your routes should be able to handle courses without having to append them with ?course_id=1:
#config/routes.rb
resources :registrations do
get :course_id, to: "registrations#new" #-> yoururl.com/registrations/:course_id
end
This will still give you the course_id param in the new action; just makes it more Rails.
--
Controller
You also need some structure in your code (you're aiming for fat model, thin controller). It looks like you're coming to Rails as a Ruby dev; you need to appreciate that Rails handles most of the exceptions etc for you.
Specifically, you need to look at how to remove code out of your actions:
def create
#registration = Registration.new registration_params
#registration.process_payment
if #registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
else
# handle error here
end
end
private
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token).merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
end
-
`id' for nil:NilClass
Finally, you have to remember this error basically means the variable you're trying to invoke an action for is nil.
Ruby populates nil variables with a NilClass object, thus it's difficult to determine what the error actually is. All it means is that the variable you're trying to call a method on doesn't have the aforementioned method, as Ruby has populated it with the NilClass object.
Try changing Registration#new action to
def new
#course = Course.find(params[:course_id])
#registration = #course.registrations.new
end
add this in your def create
def create
#course = Course.find_by id: params["registration"]["course_id"]
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
#course = Course.find_by id: params["registration"]["course_id"]
render :new
end

Rails 4 Cannot access hash in nested form (undefined method `[]' for nil:NilClass)

I've build quite complex form which creates one prescription with many realtions. I am using this syntax in view:
- provide(:title, 'Create prescription')
%h1 Add medicines to prescription
.row
.span6.offset3
= form_for #prescription do |f|
= render 'shared/error_prescription_messages'
%p
= f.hidden_field :patient_id, :value => params[:patient_id]
= f.hidden_field :user_id, :value => current_user.id
= f.fields_for :relations do |builder|
= render 'child_form', :f => builder
%p= f.submit "Submit"
chlid_form is quite simple :
- it=f.options[:child_index].to_i
- n= it.to_s
%h2
= "Medicine ##{it+1}"
= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
- if params[:prescription].nil? || params[:prescription][:relations_attributes][n.to_sym][:medicine_name].nil?
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}"
- else
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path, :id_element => "#my_medicine_id#{it}", :value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]
= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount, :value => 1
= f.label :daily
= f.number_field :daily, :value => 1
= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days, :value => 1
So as you can see I'm using f.options[:child_index] to get index of child (0,1,2...) cause I generate multiple items with this particular form. I then put it to variable it and sucessfully use it in :id_element => "#my_medicine_id#{it}" which works PERFECTLY fine (creates my_medicine_id0, my_medicine_id1 ....) Although it doesn't work in this line:
:value => params[:prescription][:relations_attributes][n.to_sym][:medicine_name]
where n is just n=it.to_s.
I though somethings wrong in controller but if I change this line to whatever
:value => params[:prescription][:relations_attributes]**[:'0']**[:medicine_name] or any other integer from 0 to 4 everything works great, but I NEED dynamic change in this one. So I got proof that it DOES work because it generates integer fine here "#my_medicine_id#{it}" but won't work in hash! And when I print the whole hash from params I get this:
{"patient_id"=>"7", "user_id"=>"1", "relations_attributes"=>{"0"=>{"medicine_id"=>"13490", "medicine_name"=>"Locacid 500 mcg/g (0,05%) (1 tuba 30 g)", "amount"=>"0", "daily"=>"1", "period_in_days"=>"1"}, "1"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "2"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "3"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}, "4"=>{"medicine_id"=>"", "medicine_name"=>"", "amount"=>"1", "daily"=>"1", "period_in_days"=>"1"}}}
so to get the values I need it's pretty obvious that
params[:prescription][:relations_attributes][SOME_KIND_OF_INETEGER][:medicine_name] should work, but doesn't.
Controller code:
class PrescriptionsController < ApplicationController
before_action :signed_in_user
before_action :doctor_user, only: [:new, :create]
before_action :pharmacist_user, only: [:update]
def new
#prescription =Prescription.new
5.times { #prescription.relations.build }
end
def create
#prescription = Prescription.new(new_prescription_params)
if #prescription.save
flash[:success] = "Prescription created."
redirect_to #prescription
else
5.times { #prescription.relations.build }
render 'new', :prescription => params[:prescription]
end
end
def show
#prescription = Prescription.find(params[:id])
#medicines = #prescription.medicines.paginate(page: params[:page], :per_page => 10)
end
def update
#prescription = Prescription.find(params[:id])
#patient = Patient.find(params[:patient_id])
if !prescription_expired?(#prescription)
#prescription.realized = 1
if #prescription.save
flash[:success] = "Prescription realized."
redirect_to #patient
else
redirect_to root_url
end
else
flash[:notice] = "Can't realize, prescription expired."
redirect_to #patient
end
end
private
def new_prescription_params
params.require(:prescription).
permit(:patient_id, :user_id, relations_attributes: [:medicine_id, :medicine_name, :amount, :daily, :period_in_days])
end
def doctor_user
redirect_to(root_url) unless current_user.function == "doctor"
end
def pharmacist_user
redirect_to(root_url) unless current_user.function == "pharmacist"
end
def prescription_expired?(presc)
presc.created_at < 1.month.ago
end
def signed_in_user
unless signed_in?
store_location
flash[:notice] = "Please log in."
redirect_to login_url
end
end
end
I run out of ideas so I ask you guys if anyone can help. Thanks.
There is no point in using params in your view since you already assigned those to your models. Also when you rendering your new action, those params doesn't exist as nothing has been send to the server yet. Just get rid of all the values from inputs.
Your partial should look like:
- it=f.options[:child_index].to_i
- n= it.to_s
%h2
= "Medicine ##{it+1}"
= f.hidden_field :medicine_id, :id => "my_medicine_id#{it}"
= f.autocomplete_field :medicine_name, autocomplete_medicine_name_relations_path
= f.label :amount, "Amount of medicine boxes"
= f.number_field :amount
= f.label :daily
= f.number_field :daily
= f.label :period_in_days, "Duration of treatment (in days)"
= f.number_field :period_in_days
If you want your fields to have default value, set default value inside your database.

Referencing and manipulating params after form submit in Rails 4 -- ActiveModel::ForbiddenAttributesError

In Rails 4, we have to change to strong parameters. I haven't figured out how to reference specific parameters yet. I keep running into this error:
ActiveModel::ForbiddenAttributesError in TransactionsController#create
When a Transaction is created, I want to manipulate some of the parameters before creating that new object. I also want to save the id of the Account (sent in the form as a hidden_field_tag).
Here is my form:
#newTransaction-modal.modal.hide.fade style="display: none;"
h3 New Transaction
= form_for Transaction.new do |f|
p Date:
= f.text_field :transaction_date, value: Time.now.strftime("%m/%d/%Y")
p Payee:
= f.text_field :payee
p Category:
= f.select :category, options_for_select(["Phone", "Restaurants", "Gas/Fuel"])
p Memo:
= f.text_field :memo
p Outflow:
= f.text_field :outflow, value: 0
p Inflow:
= f.text_field :inflow, value: 0
= hidden_field_tag :account_id, value: params[:id]
br
a.btn href="#" data-dismiss="modal" Cancel
= f.submit "Create Transaction", class: "btn"
and my Transactions controller:
class TransactionsController < ApplicationController
load_and_authorize_resource
def create
transaction_date = Date::strptime(transaction_params, "%m/%d/%Y")
outflow = params[:transaction][:outflow].include?(".") ? params[:transaction][:outflow].gsub(".", "").to_i : (params[:transaction][:outflow] + "00").to_i
inflow = params[:transaction][:inflow].include?(".") ? params[:transaction][:inflow].gsub(".", "").to_i : (params[:transaction][:inflow] + "00").to_i
#account = Account.find(params[:account][:id])
#transaction = #transaction.new(transaction_params)
#transaction.user_id = current_user.id
#transaction.account_id = #account.id
#transaction.transaction_date = transaction_date
#transaction.outflow = outflow
#transaction.inflow = inflow
#transaction.save
diff = inflow - outflow
new_account_balance = #account.balance + diff
#account.update_attributes(balance: new_account_balance)
redirect_to account_path(#account)
end
private
def transaction_params
params.require(:transaction).permit(:transaction_date, :payee, :account_id, :category, :memo, :inflow, :outflow, :user_id)
end
end
How do I reference the account_id in my controller?
I would allow the params of the account as well. You can add {account_attributes: {:id}} to the transaction_params method and that will allow it. Then you can call transaction_params and get back the hash of params that you are free to modify as you please.

Rails problem display attribute key along with attributes value

I have the following problem. I have a form which takes input for a "Chart" object. But after processing the form, i wish to display one of the values, and it adds the key of this value.
Class model
class Chart
attr_accessor :title, :series
def initialize(title = nil, series = [])
#title, #series = title, series
end
end
View of form:
<% form_for :chart , :url => { :action => "show" } do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>...
<% end %>
Chart controller, show method:
def show
#chart = Chart.new(params[:chart])
end
View of show:
<h2><%=h #chart.title %></h2>
Which displays: "title"input_forms_title""
for example: writing in the input form: Economy, prints in the show view: "titleEconomy"
Any ideas?
I have just figured it out. The problem was in the constructor or initialize method. By changing the initialize method to:
def initialize( options = {} )
#title = options[:title]
#series = []
end
It now accepts all params perfectly!

Resources