How to complete form fields automatically in Ruby On Rails

How to complete form fields automatically in Ruby On Rails



Regards! I am creating an inventory system in which, at the time of making the sale, I need to write the code or product name, I need to get the price out of it, without the need to write it manually, however, I have little knowledge of javascript, I have found several resources like autocomplete of jquery, however, I can not do it, I followed the tutorial of RailsCasts about dynamic selectors, nevertheless I need this to be achieved with text fields, I appreciate immensely someone can help me, specifically in the output model, I have the items in the output_item model, and my product model:



output_form.html.erb


<%= form_with(model: output, local: true, id: "form") do |f| %>

<div class="form-group">
<%= f.label :invoice %> <br>
<%= f.text_field :invoice, class: "form-control", placeholder: "CE0001" %>
</div>

<div class="form-group">
<%= f.label :customer %> <br>
<%= f.text_field :customer, class: "form-control", placeholder: "Ej. Jeovanny" %>
</div>

<table width="100%" id="output-item">
<thead>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
<th>Options</th>
</thead>
<tbody>
<%= f.fields_for :output_items, id: "form" do |item| %>
<%= render "output_item_fields", f: item %>
<% end %>
</tbody>
</table>

<div class="form-group mb-0">
<%= link_to_add_association 'Add product', f, :output_items, :"data-association-insertion-node" => "table#output-item",:"data-association-insertion-method" => "append", class: "btn btn-success" %>
</div>

<div class="form-group>
<%= link_to "Cancelar", outputs_path, class: "btn btn-danger" %>
<%= f.submit "Send", class: "btn btn-primary" %>
</div>

<% end %>



output_items_fields.html.erb


<tr class="item">
<td><%= f.text_field :product_id, class: "form-control field" %></td>
<td><%= f.text_field :quantity, class: "form-control field quantity" %></td>
<td><%= f.text_field :price, class: "form-control field price" %></td>
<td><input type="text" class="form-control field subtotal"></td>
<td class="text-center">
<%= link_to_remove_association f, wrapper_class: "item", class: "btn btn-danger" do %>
<i class="fal fa-trash-alt"></i>
<% end %>
</td>
</tr>



product.rb


class Product < ApplicationRecord

has_many :input_items
has_many :output_items
validates :code, :name, presence: true

def purchase
input_items.pluck(:quantity).sum
end

def sale
output_items.pluck(:quantity).sum
end

def stock
(input_items.pluck(:quantity).sum - output_items.pluck(:quantity).sum)
end

def price
self.input_items.sum(:price) / self.input_items.count
end

end



Output.rb


class Output < ApplicationRecord

has_many :output_items, inverse_of: :output, :dependent => :delete_all
accepts_nested_attributes_for :output_items, reject_if: :all_blank, allow_destroy: true

validates :invoice, :provider, presence: true

end



output_item.rb


class OutputItem < ApplicationRecord

belongs_to :product
belongs_to :output
validates :quantity, :price, numericality: true, presence: true

end

class Product < ApplicationRecord

has_many :output_items

end



input.rb


class Input < ApplicationRecord

has_many :input_items, inverse_of: :input, :dependent => :delete_all
accepts_nested_attributes_for :input_items, reject_if: :all_blank, allow_destroy: true

validates :invoice, :provider, presence: true

end



input_item.rb


class InputItem < ApplicationRecord

belongs_to :product
belongs_to :input
validates :quantity, :price, numericality: true, presence: true

end



input_migrate.rb


class CreateInputs < ActiveRecord::Migration[5.2]
def change
create_table :inputs do |t|
t.string :invoice
t.string :provider

t.timestamps
end
end
end



input_items_migration.rb


class CreateInputItems < ActiveRecord::Migration[5.2]
def change
create_table :input_items do |t|
t.integer :product_id
t.float :quantity
t.float :price
t.belongs_to :input, foreign_key: true

t.timestamps
end
end
end



product_migrate.rb


class CreateProducts < ActiveRecord::Migration[5.2]
def change
create_table :products do |t|
t.string :code
t.string :name
t.float :utility

t.timestamps
end
end
end



output_migrate.rb


class CreateOutputs < ActiveRecord::Migration[5.2]
def change
create_table :outputs do |t|
t.string :invoice
t.string :customer

t.timestamps
end
end
end



output_item_migrate.rb


class CreateOutputItems < ActiveRecord::Migration[5.2]
def change
create_table :output_items do |t|
t.integer :product_id
t.float :quantity
t.float :price
t.belongs_to :output, foreign_key: true

t.timestamps
end
end
end



The code that RailsCast offers, to autocomplete selectors is with:


(function()
jQuery(function()
var states;
$('#input_price').parent().hide();
states = $('#input_price').html();
return $('#input_product_id').change(function()
var country, escaped_country, options;
country = $('#input_product_id :selected').text();
escaped_country = country.replace(/([ #;&,.+*~':"!^$[]()=>);
);

).call(this);



In what way could adapt, or what is the most convenient way to do this, as an added data, I use cocoon for dynamic items, I appreciate immensely, can help me, Regards!



Updates



output_items_fields.html.erb


<tr class="item">
<td><%= f.text_field :product_id, class: "form-control field" %></td>
<td><%= f.text_field :quantity, class: "form-control field quantity" %></td>
<td><%= f.text_field :price, class: "form-control field price" %></td>
<td><input type="text" class="form-control field subtotal"></td>
<td class="text-center">
<%= link_to_remove_association f, wrapper_class: "item", class: "btn btn-danger" do %>
<i class="fal fa-trash-alt"></i>
<% end %>
</td>
</tr>

<% content_for :javascript do %>
<script type="text/javascript">var product_info = $.parseJSON('<%= @product_info.to_json.html_safe %>');</script>
<% end %>

<% content_for :javascript do %>
<script type="text/javascript">
var product_info = $.parseJSON('<%= @product_info.to_json.html_safe %>');
(function()
jQuery(function()
var product = product_info[$('#output_product_id')]
return $('#output_product_id').change(function()
if (product)
$('#output_price').val(product.price);
$('#output_description').val(product.description);
else
$('#output_price').val("");

);
);
).call(this);
</script>
<% end %>



outputs_controller.rb


class OutputsController < ApplicationController
before_action :set_output, only: [:show, :edit, :update, :destroy]

def new
@output = Output.new
@output.output_items.build
@product_info = Product.joins(:input_items).select(:price).all.inject() a[b.input_items] = price: b.price
end
end



When I look for the product_info and testing in the browser console, I get it:


console.log(product_info)
Object price: null
debugger eval code:1:1
undefined

console.log('testing')
testing debugger eval code:1:1
undefined





When you say "I need to write the code or product name, I need to get the price out of it, without the need to write it manually" what exactly do you mean? Where does the price come from? Does it from from the product name? Do you do a query to get the price when the user enters a product name or code?
– Billy Kimble
Aug 29 at 2:51





Regards blimbe! I just updated the post, and added my Input model, and InputItem, to make the purchase I store the price within InputItem, which in turn belongs to an Input and a product, when stored within purchase, when I am making a sale, I call the product, and this refers to the price that was added from purchase (InputItem)
– Hector Hernandez
Aug 29 at 2:59





Basically, it's like when you go to the supermarket, scan the code, and automatically appears the description, and price of the product, basically what I'm trying to do, that when selecting or adding the code, complete the fields at the same time, with respective description and price
– Hector Hernandez
Aug 29 at 3:02





So, you would be entering the code of the item(meaning do you want to autocomplete here or user enters the code manually) and then you want to auto populate the information such as the price, description of that item ?
– Kedarnag Mukanahallipatna
Aug 29 at 3:17






Exactly Kedarnag, when entering the code within the field (product_id), which is located in the partial output_items_fields.html.erb, I must automatically fill in the "price" field, and I have to add a field that in this case is called the name of the product, which would be product_id, set with its respective name
– Hector Hernandez
Aug 29 at 3:21




1 Answer
1



As long as you don't have a very large number of products, this is how I would tackle this to auto populate based on model number (if I understand your requirements correctly). You essentially need to get a Javascript representation of all of your product data, then feed that to jQuery to do the populating, similar to how the Railscast was using country name. And lucky for you, you can easily convert a ruby Hash or Array in to something Javascript can see using .to_json.



First, create a hash that has a key of product model to product price, and populate it from your data source:


@product_info = Product.select(:code,:price).all.inject() a, b



And put that in your controller action.



Next, get that instance variable in to a Javascript variable on your page. This part depends on if you are set up to use content_for :javascript - see Including inline javascript using content_for in rails .


<% content_for :javascript do %>
<script type="text/javascript">
var product_info = $.parseJSON(<%= @product_info.to_json.html_safe %>);
</script>
<% end %>



The finally, add this take on the Railscast Code to the content_for block and make it look like the following (replacing the old content_for :javascript block). This part is up to you - if you want a text box that is just populated, or if you want what they had, where you hide and show the field if you can find the values in the hash. I just made it populate it if it could find it, or make it a blank string if it couldn't


<% content_for :javascript do %>
<script type="text/javascript">
var product_info = $.parseJSON(<%= @product_info.to_json.html_safe) %>;
(function()
jQuery(function()
return $('#input_product_id').change(function()
if (var product = product_info[$('#input_product_id')])
$('#input_price').val(product.price);
else
$('#input_price').val("");

);
);
).call(this);
</script>
<% end %>



Now this would work decently as a first iteration, but there are some issues with it that may apply to you, depending on how you are set up.



The more products you have, the more data you have to spit out as a JSON string. If that string becomes 2, 4, 10 megabytes, it will really slow your users down as they have to load that data just to view your page. You can mitigate that by going a different route and firing off an AJAX call to get the product data as the user types in the model number, and populate the fields as we're doing here. It's not that much more work to go that route as long as you're OK with having an endpoint that gets hit every time the user types something in a text field, and the corresponding database call it needs to make to do the searching.



The other issue is that every time the page loads, you will be re-fetching all of your product data. You would need to start thinking about caching that data either in the view, or in the controller, so that you always load the product model->price/description map from cache instead of fetching it from the database.



Finally, if some other user is entering product information which you want available to power your auto populate code, it would require a page reload. If you don't have that many products being added/changed, this isn't as big of a concern, but if it changes multiple times per minute/hour, you may want to think about going with the aforementioned solution which fires an AJAX call every time the user types something in, so you can be guaranteed of the latest Product information being returned, rather that some potentially stale representation of all of your product information.





Greetings, I have implemented the idea, I have applied the code, I have corrected some small syntax errors, but I still do not complete the field, and the console is clean
– Hector Hernandez
Aug 29 at 16:44





Can you confirm in browser dev tools console that you can see the product_info variable ? open browser console and do : console.log(product_info). Can you also confirm that the jQuery onChange handler is firing by adding a console.log('testing') right after $('#input_product_id').change(function(), reloading the app, changing the text value, and looking at your browser dev tools console? Lastly please suggest edits for syntax errors so I can fix them :)
– Billy Kimble
Aug 29 at 17:50





bkimble, I just updated the post, with the changes I made
– Hector Hernandez
Aug 29 at 20:45





Awesome. Can you let me know if your onChange handler is firing, and if you can see the JSON object in JS console? Also two things I noticed: 1: you don't see to have an 'output_description' id on any of your fields. I'm not sure which is supposed to represent description, but that should match the ID of that field. and 2: you have the content_for :javascript block in there twice. you only need the bottom one. I was building up the code in the example so I could explain what each step was
– Billy Kimble
Aug 29 at 20:50






bkimnle, I update the post again with the tests in the browser console
– Hector Hernandez
Aug 29 at 20:54






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)