Итак, у меня есть эта проблема. У меня есть модель 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) для построения веб-сервисов.
В этом случае вам не нужно использовать сильные параметры. Я бы написал метод контроллера так:
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