Как заполнить поля формы автоматически в Ruby On Rails - PullRequest
0 голосов
/ 29 августа 2018

Привет! Я создаю систему инвентаризации, в которой во время совершения продажи мне нужно написать код или название продукта, мне нужно получить цену, без необходимости писать это вручную, однако у меня мало Знание javascript, я нашел несколько ресурсов, таких как автозаполнение jquery, однако, я не могу этого сделать, я следовал учебнику RailsCasts по динамическим селекторам, тем не менее мне нужно, чтобы это было достигнуто с помощью текстовых полей, я очень ценю, что кто-то может мне помочь В частности, в выходной модели у меня есть элементы в модели output_item и модель моего продукта:

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

Код, который предлагает RailsCast для автозаполнения селекторов:

(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(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
        options = $(states).filter("optgroup[label='" + escaped_country + "']").html();
        if (options) {
          $('#input_price').html(options);
          return $('#input_price').parent().show();
        } else {
          $('#input_price').empty();
          return $('#input_price').parent().hide();
        }
      });
    });

  }).call(this); 

Каким образом можно было бы адаптироваться, или какой самый удобный способ сделать это, в качестве дополнительных данных я использую кокон для динамических предметов, я очень благодарен, могу помочь мне, С уважением!


Обновление

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| a[b.input_items] = {price: b.price}}  
  end
end

Когда я смотрю на product_info и тестирую в консоли браузера, я получаю:

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

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

1 Ответ

0 голосов
/ 29 августа 2018

До тех пор, пока у вас нет очень большого количества продуктов, именно так я бы использовал автоматическое заполнение на основе номера модели (если я правильно понимаю ваши требования). По сути, вам нужно получить представление Javascript всех данных вашего продукта, а затем передать его в jQuery для заполнения, подобно тому, как Railscast использовал название страны. И, к счастью для вас, вы можете легко конвертировать рубиновый Hash или Array в то, что Javascript может увидеть, используя .to_json.

Сначала создайте хеш, который имеет ключ модели продукта к цене продукта, и заполните его из источника данных:

@product_info = Product.select(:code,:price).all.inject({}) {|a, b| a[b.code] = {price: b.price}}

И поместите это в действие вашего контроллера.

Далее, добавьте эту переменную экземпляра в переменную Javascript на вашей странице. Эта часть зависит от того, настроены ли вы на использование content_for: javascript - см. Включение встроенного javascript с использованием content_for в rails .

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

Наконец, добавьте этот пример кода Railscast в блок content_for и сделайте его похожим на следующий (заменив старый блок content_for: javascript). Эта часть зависит от вас - если вы хотите, чтобы текстовое поле было только что заполнено, или если вы хотите, чтобы они имели, где вы прячете и показываете поле, если вы можете найти значения в хэше. Я просто заполнил его, если смог найти, или сделал пустую строку, если не смог

<% 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 %>

Проблемы / альтернативы

Теперь это будет неплохо работать в качестве первой итерации, но есть некоторые проблемы с ним, которые могут относиться к вам, в зависимости от того, как вы настроены.

Чем больше у вас продуктов, тем больше данных вы должны выложить в виде строки JSON. Если эта строка станет 2, 4, 10 мегабайт, это действительно замедлит работу ваших пользователей, поскольку им придется загружать эти данные только для просмотра вашей страницы. Вы можете уменьшить это, выбрав другой маршрут и вызвав вызов AJAX, чтобы получить данные о продукте, когда пользователь вводит номер модели, и заполнять поля, как мы делаем здесь. Не так много работы по этому маршруту, если у вас все в порядке с конечной точкой, которая срабатывает каждый раз, когда пользователь вводит что-то в текстовое поле, и соответствующим вызовом базы данных, который он должен выполнить для поиска.

Другая проблема заключается в том, что при каждой загрузке страницы вы будете повторно получать все данные о вашем продукте. Вам нужно подумать о кэшировании этих данных либо в представлении, либо в контроллере, чтобы вы всегда загружали модель продукта-> карту цены / описания из кэша, а не извлекали ее из базы данных.

Наконец, если какой-либо другой пользователь вводит информацию о продукте, которую вы хотите использовать для автоматического заполнения кода, это потребует перезагрузки страницы. Если у вас не так много продуктов, добавляемых / изменяемых, это не такая большая проблема, но если она меняется несколько раз в минуту / час, вы можете подумать о том, чтобы использовать вышеупомянутое решение, которое запускает AJAX. звоните каждый раз, когда пользователь что-то вводит, так что вы можете быть уверены в том, что будет возвращена самая последняя информация о продукте, а не в том, что некоторые могут потерять представление всей информации о вашем продукте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...