Как обновить все записи сотрудников суммой текущего значения и одной из формы ввода

Итак, у меня есть эта проблема. У меня есть модель Employee, которая находится под администраторами пространства имен. и в таблице сотрудников у меня есть столбец «number_of available_kudos». Допустим, значение каждой строки отличается. И я хочу иметь форму, которая вводит значение в диапазоне от 1 до 20 и добавляет одно и то же значение к каждой строке. И маршруты редактирования и обновления взяты, поэтому я создал 2 пользовательских метода, подобных этому:

module Admins
  class EmployeesController < AdminController
    def index
      @employees = Employee.all
    end

    def edit
      @employee = Employee.find(params[:id])
    end

    def edit_add_kudos_to_all
      @employee = Employee.all
      render 'admins/employees/update_add_kudos_to_all'
    end

    def update_add_kudos_to_all
      Employee.transaction do
      Employee.find_each do |employee|
        employee.update!(add_kudo_to_all_params)
        employee.number_of_available_kudos =+ employee.number_of_available_kudos
        flash[:notice] = 'Successfully updated the numer of kudos to all employees'

      rescue ActiveRecord::RecordInvalid
        flash[:notice] = 'The numer of kudos you want to add is too high'
        redirect_to admins_kudo_path
        end
    end
    end

    def destroy
      @employee = Employee.find(params[:id])
      flash[:notice] = if @employee.destroy
                         'Employee account was deleted successfully'
                       else
                         'Employee account deletion failed'
                       end
      redirect_to admins_employees_path
    end

    def update
      @employee = Employee.find(params[:id])
      if @employee.update(employee_params)
        flash[:notice] = 'Employee was edited successfully'
        redirect_to admins_employees_path
      else
        render 'admins/employees/edit'
      end
    end

    private

    def employee_params
      params.require(:employee).permit(:email, :password, :number_of_available_kudos)
    end

    def add_kudo_to_all_params
      params.fetch(:employee, {} ).permit(:number_of_available_kudos)
    end
  end
end

А вот и мои маршруты

# frozen_string_literal: true

Rails.application.routes.draw do
  devise_for :admins, path: 'admins'
  devise_for :employees, path: 'employees'
  namespace :employees do
    resources :kudos
    resources :rewards, only: [:index, :show]
    resources :orders, only: [:create, :index, :show]
  end
  namespace :admins do
    resources :kudos, only: [:index, :destroy]
    patch 'update_add_kudos_to_all/', to: 'employees#update_add_kudos_to_all'
    get  'edit_add_kudos_to_all/', to: 'employees#edit_add_kudos_to_all'
    resources :employees, only: [:index, :edit, :update, :destroy] do
      resources :orders, only: [:index, :update]
     # patch 'mass_edit/', to: 'mass_edit#update'
     # get 'mass_edit/', to: 'mass_edit#edit'
      end
    namespace :employees do
      resources :orders, only: [:index, :update]
    end
    resources :company_values
    resources :rewards


  end
  get '/admin' => "admins/pages#dashboard", :as => :admin_root
  root 'employees/kudos#index'
end

И, наконец, вот моя форма update_add_kudos_to_all

<h1>Edit number of available kudos to all Employees</h1>

<%= form_with url: 'update_add_kudos_to_all', method: :patch  do |f| %>

  <p>
    <%=f.label :number_of_available_kudos %><br/>
    <%= f.number_field :number_of_available_kudos %>  </p>
  <p>
    <%= f.submit %>
  </p>

<% end %>

О, и я также вставлю ссылку_в форму редактирования

<p> <%= link_to 'Add Kudos to all', admins_edit_add_kudos_to_all_path, method: :get %></p>

Прямо сейчас результат таков, что все успешно (по крайней мере, так говорят), и значения не складываются. Я чувствую, что мне здесь не хватает чего-то основного. Поэтому, пожалуйста, помогите мне разобраться в этом.

🤔 А знаете ли вы, что...
Ruby on Rails активно соблюдает принцип REST (Representational State Transfer) для построения веб-сервисов.


51
1

Ответ:

Решено

В этом случае вам не нужно использовать сильные параметры. Я бы написал метод контроллера так:

def update_add_kudos_to_all
  Employee.transaction do
    Employee.find_each do |employee|
      employee.increment(
        :number_of_available_kudos, params[:number_of_available_kudos].to_i
      )
      employee.save!
    end
      
    flash[:notice] = 'Successfully updated the number of kudos to all employees'
  rescue ActiveRecord::RecordInvalid
    flash[:notice] = 'The number of kudos you want to add is too high'
    redirect_to admins_kudo_path
  end
end

Или, когда проверка действительно не требуется, вы можете использовать update_all, который выполняет один SQL-запрос и, следовательно, будет намного быстрее:

def update_add_kudos_to_all
  Employee.in_batches.update_all(
    "number_of_available_kudos = number_of_available_kudos + #{params[:number_of_available_kudos].to_i}"
  )
end

Чтобы ответить на ваш дополнительный вопрос из комментариев: я бы проверил, действительно ли количество новых доступных kudos в контроллере, и если это так, я бы использовал метод update_all, как указано выше. Но поскольку вы спросили, как совместить это с update, следующий пример представляет собой комбинацию этих двух подходов:

def update_add_kudos_to_all
  new_available_kudos = params[:number_of_available_kudos].to_i

  if (1..20).cover?(new_available_kudos)
    Employee.find_each do |employee|
      employee.update(
        number_of_available_kudos: employee.number_of_available_kudos + new_available_kudos
      )
    end

    flash[:notice] = 'Successfully updated the number of kudos to all employees'
  else
    flash[:notice] = 'Invalid number of kudos, must be between 1 and 20.'
    redirect_to admins_kudo_path
  end