I am encountering a minor problem with some javascripts/AJAX and i was hoping someone can help me or point me to the right direction.
What I am trying to do is to populate my per-carton-price-field using collection_select in the same form. This is an order form which is suppose to create an entry into my order table. Form view as below:
new.html.erb
<h1>Add a new order for <%= #customer.name %></h1>
<div class="row">
<%= form_for(#order) do |f| %>
<div class="col-md-6">
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :customer_id, :value => #customer.id %>
<h3>Order Details</h3>
<%= f.label :address_id, "Delivery Address" %>
<%= f.collection_select :address_id, #addresses, :id, :select_address, :prompt => "Select delivery location",class: 'form-control' %></br>
<%= f.label :remark, "Order Remark" %>
<%= f.text_area :remark, class: 'form-control' %></br>
<h3>What items would you like to place?</h3>
<%= f.add_nested_fields_link :single_orders, "Add Product" %>
<%= f.nested_fields_for :single_orders do |builder| %>
<%= builder.collection_select :product_id, #products, :id, :select_product, {:prompt => "choose product"}, {:class => "product_selection form-control"} %>
<%= builder.text_field :ctn_price, placeholder: "Price/carton", id: "price", class: 'ctn_price_field form-control' %>
<%= builder.text_field :qty, placeholder: "Quantity",id: "quantity", class: 'form-control' %>
<%= builder.text_field :price, placeholder: "Amount", id: "total-amount", readonly: true, class: 'form-control' %>
<%= builder.remove_nested_fields_link %>
<% end %>
</div>
<%= f.submit "place order", class: "btn btn-primary" %>
<% end %>
</div>
I would like the collection_select:product_id to pull out all the products in the products table. When the user selects whichever product they want to order from the dropdown, the price for the selected product will populate the text_field:ctn_price.
product.rb
class Product < ActiveRecord::Base
has_many :special_prices, dependent: :destroy
has_many :single_orders
has_many :package_orders_products
before_save :upcase_stock_code
validates :name, presence: true, length: { maximum: 50 }
validates :stock_code, presence: true, length: { maximum: 20 }
validates :status, presence: true, length: { maximum: 10 }
validates :price, presence: true
private
def select_product
"#{name} - #{price}"
end
# Converts stock_code to all upper-case.
def upcase_stock_code
self.stock_code = stock_code.upcase
end
end
single_order.rb
class SingleOrder < ActiveRecord::Base
belongs_to :order
belongs_to :product
validates :order, presence: true
validates :product_id, presence: true
validates :qty, presence: true
validates :price, presence: true
validates :ctn_price, presence: true
end
Any help is appreciated as I have been stuck for days :(
Thanks for any help in advance.
You can do this using ajax call. Before that create a api to take product_id as input and render #product as output.
$("#product_selection_id").on('change', function(){
var product_id = $(this).val();
$.ajax({
method: "GET",
type: 'html',
url: "call_url_for_get_product_api_with_product_id",
cache: false,
success: function(data, textStatus, jqxhr) {
console.log("success");
}
});
});
Suppose your url_for_get_product_api goes to get_product action as a js request. so create a template with get_product.js.erb as follows
$('#ctn_price_field').val(#product.price)
#ihave not tested this code change this according to your requirements.
Note: Here i have given a pattern impliment this by your own. Thanks.
Related
I have an index page where I have to filter Invoices by due_date to prepare them for mass edition. The idea is to keep the submit button disabled until a start_date and end_date have been selected.
I have the following simple_form working with flatpickrJS and I have added data-targets to it's input fields:
<div class="col-md-6 my-2">
<%= simple_form_for :date_params, { url: admin_invoices_batch_edit_index_path, method: :get } do |f| %>
<%= f.input :start_date, as: :string, placeholder: "Start date for filter",
input_html: { data:{ controller: "flatpickr", target: "required",
attributes:{ enableTime: false, enableSeconds: false } } }
%>
<%= f.input :end_date, as: :string, placeholder: "End date for filter", input_html: { data:{ controller: "flatpickr", target: "required",
attributes:{ enableTime: false, enableSeconds: false } }
}
%>
<%= f.button :submit, "Filtrar por fecha" %>
<% end %>
</div>
I also have this other simple_form to select a due_date to which all Invoices will be updated, and I need to keep this form's submit button disabled until all required targets have been selected (that is until a start and end date has been selected in the first form).
<div class="col-md-6 my-2" data-controller="activable">
<%= simple_form_for :due_date, { url: admin_invoices_batch_edit_index_path } do |f| %>
<%= f.input :due_date, as: :string, placeholder: "Nueva fecha de recibo",
input_html: { data:{ controller: "flatpickr",
attributes:{ enableTime: false, enableSeconds: false } } }
%>
<% if params[:date_params].present? %>
<%= hidden_field_tag :start_date, params[:date_params][:start_date] %>
<%= hidden_field_tag :end_date, params[:date_params][:end_date] %>
<% end %>
<%= f.button :submit, "Update Invoices", id: "deactivable-submit", disabled: true %>
<% end %>
</div>
This is my Stimulus controller but I don't know how to check that all requiredTargets have been selected so the disabled button gets enabled.
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['deactivable required']
initialize() {
}
connect() {
this.requiredTargets.forEach((element) => {
element.config.onChange.push(function() { } ); })
// check that all required targets have been selected?
}
toggle(){
this.deactivableTargets.toggleAttribute("disabled");
}
}
My dashboard.rb is:
ActiveAdmin.register_page "Dashboard" do
menu priority: 1, label: proc{ I18n.t("active_admin.dashboard") }
content title: proc{ I18n.t("active_admin.dashboard") } do
# form render 'form'
# Here is an example of a simple dashboard with columns and panels.
columns do
column class: "users" do
table_for User.all.order(:created_at), input_html: { class: "table table-bordered" } do
column "User Id", :id
column "Email", :email
column "User Role" do |role|
role.profile.role
end
end
end
column do
render partial: 'form', locals: { club: Club.new }
end
end
end
end
My form partial is in app/views/admin/dashboard/_form.html.erb and it is:
<%= semantic_form_for :club, url: admin_clubs_url, method: :post, builder: ActiveAdmin::FormBuilder, remote: true do |club| %>
<%= club.inputs "Details" do %>
<%= club.input :name, label: 'Club Name' %>
<%= club.input :email, label: 'Club Admin Email', input_html: { value: '' } %>
<%= club.inputs for: [:club_profile_attributes] do |ff| %>
<%= ff.input :country_id, as: :select, collection: Country.get_id_and_name, include_blank: false %>
<%= ff.input :logo, as: :file %>
<%= ff.input :email, label: 'Club Email' %>
<%= ff.input :phone_number_1, label: 'Phone Number' %>
<% end %>
<%= club.actions %>
<% end %>
Now how do I use an ajax request to update my users in dashboard.rb file, so whenever I create a club my user list gets updated using the ajax request/response.
$('#form_id').on('ajax:success', function(event, data, status, xhr){});
ajax:success and other custom events can be used to handle responses from remote: true forms. You would need to send the updated user list with the response data and then append or replace the user list.
I have a problem with my nested attributes. I want someone to be able to just visit my website and add songs to an event. They can only add those songs if they supply a partycode for that event. I have my nested attributes set up correctly I think but I am getting an unpermitted paramter error.
Events controller:
class EventsController < ApplicationController
def new
#event = Event.new
#event.songs.build
end
def show
#event = Event.find(params[:id])
#songs = #event.songs.paginate(page: params[:page])
end
def create
#event = current_user.events.build(event_params)
if #event.save
flash[:success] = "Event Created!"
redirect_to user_path(#event.user)
else
render 'welcome/index'
end
end
def destroy
end
private
def event_params
params.require(:event).permit(:name, :partycode, song_attributes: [:artist, :title, :genre, :partycode])
end
end
application_controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
end
Here is the new.html.erb file in the songs view, which contains the code to add songs to the event, note that the user is not signed in when they are adding songs:
<br>
<br>
<div class ="container">
<div class="jumbotron">
<%= form_for Event.new do |f| %>
<h3>Enter a song:</h3>
<%= f.fields_for :songs, Song.new do |song_form| %>
<%= song_form.collection_select(:event_id, Event.all, :id, :name) %>
<%= song_form.text_field :artist, placeholder: "Artist" %>
<%= song_form.text_field :title, placeholder: "Title" %>
<%= song_form.text_field :genre, placeholder: "Genre" %>
<% end %>
<%= link_to_add_fields "Add Song", f, :songs %>
<%= f.text_field :partycode %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
The link_to_add_fields method is in the application_helper.rb file:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render("songs_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
The songs_field partial is defined as follows:
<fieldset>
<%= f.text_field :artist, placeholder: "Artist" %>
<%= f.text_field :title, placeholder: "Title" %>
<%= f.text_field :genre, placeholder: "Genre" %>
</fieldset>
The coffee-script that adds the fields:
$(document).on 'click', 'form .add_songs', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('event_id'), 'g')
$(this).before($(this).data('songs').replace(regexp, time))
event.preventDefault()
The person from the new.html.erb page will be able to select a event from the drop down menu then on demand add more fields that are for a song and then enter a partycode for the certain event that they picked. Any help on this would be fantastic! Thanks
EDIT error:
undefined method `events' for nil:NilClass
In your EventsController, your nested params is spelled as song_attributes in event_params method
private
def event_params
params.require(:event).permit(:name, :partycode, song_attributes: [:artist, :title, :genre, :partycode])
end
But your error says unpermitted parameter: songs_attributes.
You spelled it incorrect.Change your event_params method in EventsController as follows
private
def event_params
params.require(:event).permit(:name, :partycode, songs_attributes: [:artist, :title, :genre, :partycode])
end
Im trying to update my create item action to work with Ajax but Im getting an error of undefined methoditem_path` which i wasn't getting before when it was responding in regular html format. The item is created and saved but ajax doesn't seem to work properly though.
Here is my _from partial :
<%= form_for [#user, item], remote: true do |f|%>
<div class="form-group">
<%= f.label :name, class: 'sr-only' %>
<%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
</div>
<%= f.submit "Submit Item", class: 'btn btn-primary pull-right' %>
<% end %>
item#create:
def create
#item = Item.new(item_params)
#item.user = current_user
if #item.save
flash[:notice] = 'Item saved successfully.'
else
flash[:alert] = 'Item not saved. Title is too short or missing. Please try again.'
end
respond_to do |format|
format.html
format.js
end
end
create.js.erb:
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: {user: #user , item: #item }) %>");
User#show view
<div class='new_item'>
<%= render :partial => 'items/form', :locals =>{:item => Item.new , :user => #user} %>
</div>
<div class='js-items'>
<%= render #user.items %>
</div>
routes:
user_items GET /users/:user_id/items(.:format) items#index
POST /users/:user_id/items(.:format) items#create
new_user_item GET /users/:user_id/items/new(.:format) items#new
edit_user_item GET /users/:user_id/items/:id/edit(.:format) items#edit
user_item GET /users/:user_id/items/:id(.:format) items#show
PATCH /users/:user_id/items/:id(.:format) items#update
PUT /users/:user_id/items/:id(.:format) items#update
DELETE /users/:user_id/items/:id(.:format) items#destroy
The error im getting in rails s :
ActionView::Template::Error (undefined method `item_path' for #<#<Class:0x007fa4f0d30cd8>:0x007fa4f31b26b0>):
1: <%= form_for [#user, item], remote: true do |f|%>
2: <div class="form-group">
3: <%= f.label :name, class: 'sr-only' %>
4: <%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
app/views/items/_form.html.erb:1:in `_app_views_items__form_html_erb__331698480542899910_70173200751480'
app/views/items/create.js.erb:2:in `_app_views_items_create_js_erb___3618987352886002527_70173200313760'
app/controllers/items_controller.rb:17:in `create'
Do something like that.
<%= form_for [#user, item], user_items, remote: true do |f|%>
If it doesn't work then run
rake routes
in terminal see what's your path.
I'm trying to use jQuery Tokeninput as shown in Railscast #258 (revised). When I enter something in the tokeninput field, the field does not dropdown with results and I get the following javascript error: Uncaught TypeError: Cannot call method 'replace' of undefined.
My json data works fine when I do a manual query on it, and the server request looks fine. I am trying to search the content column in my issues table, so I set propertyToSearch to "content".
Here is my code:
coffeescript:
jQuery ->
$('#fact_issue_tokens').tokenInput "/issues.json"
theme: 'facebook'
zindex: 11001
propertyToSearch: 'content'
tokenValue: 'content'
hintText: 'Enter an issue'
preventDuplicates: true
Issue Model:
def self.tokens(query)
issues = where("content like ?", "%#{query}%")
if issues.empty?
[{id: "<<<#{query}>>>", content: "New: \"#{query}\""}]
else
issues
end
end
def self.ids_from_tokens(tokens)
tokens.gsub!(/<<<(.+?)>>>/) { create!(content: $1).id }
tokens.split(',')
end
Issues Controller:
def index
#issues = Issue.order(:content)
respond_to do |format|
format.html
format.json { render json: #issues.tokens(params[:q]) }
end
end
Form:
<%= form_for(Fact.new, :url => kase_facts_path(current_kase), :html => {:class => "form-
inline"}) do |f| %>
<%= f.text_field :page, placeholder: 'Page' %>
<%= f.text_field :description, placeholder: 'Description' %>
<%= f.label :issue_tokens, 'Issue tags' %>
<%= f.text_field :issue_tokens %>
<%= f.hidden_field :source_id, :value => #source.id %>
<%= f.submit 'Add Fact' %>
<% end %>
#Scott you try this
jQuery ->
$('#fact_issue_tokens').tokenInput '/issues.json'
theme: 'facebook'
tokenLimit: 5
minChars: 4
preventDuplicates: true
searchingText: "Enter an issue..."
prePopulate: $('#fact_issue_tokens').data('load')
and think on your index because you are using (:content) not name might be your problem. I am bot sure why but i used title and i had a problem, i thought it was mysql or something.
When you visit
http://localhost:3000/issues.json
Do you get the JSON data?
Edit.
Can you please try this for your form?
<div class="field">
<%= f.label :issue_tokens, "Issues" %><br />
<%= f.text_field :issue_tokens, data: {load: #fact.issues} %>
</div>