【发布时间】:2018-01-25 02:17:44
【问题描述】:
我的交易模型使用以下控制器逻辑根据数量(整数列)生成唯一票号数组:
@transaction.quantity.times.uniq { @transaction.ticket_numbers << rand(100000..999999) }
但是,这只能确保数组中的数字是唯一的。
我需要一个检查所有 Transaction.ticket_numbers 数组的数据库验证,以确保每个值(票号)在所有数组中都是唯一的。
这是我在 schema.rb 中的事务表:
create_table "transactions", force: :cascade do |t|
t.string "payee"
t.integer "quantity"
t.decimal "debt", precision: 8, scale: 2
t.string "email"
t.string "ministry"
t.integer "status"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "ticket_numbers", default: [], array: true
end
来自 transaction.rb 的交易模型:
require 'csv'
class Transaction < ApplicationRecord
belongs_to :user
validates :email, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/, :on => [:create, :update] }
validates :payee, presence: true
validates :quantity, numericality: { greater_than_or_equal_to: 1 }
validates :debt, numericality: { greater_than_or_equal_to: 0 }
def self.to_csv
attributes = %w{payee email ministry quantity debt status ticket_numbers}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |transaction|
csv << attributes.map{ |attr| transaction.send(attr) }
end
end
end
end
事务控制器:
class TransactionsController < ApplicationController
before_action :load_transaction, only: [:edit, :update, :destroy]
def create
@transaction = Transaction.new(transaction_params)
if @transaction.save
@transaction.quantity.times.uniq { @transaction.ticket_numbers << rand(100000..999999) }
end
@user = @transaction.user
@transactions = @user.transactions
respond_to do |format|
if @transaction.save && @transaction.status == 1
UserMailer.payment_confirmation(@transaction).deliver_later
format.html { redirect_to user_url(@user), notice:'Transaction added & ticket sent' }
format.json { render json: @user, status: :created, location: @user }
elsif @transaction.save && @transaction.status != 1
format.html { redirect_to user_url(@user), notice:'Transaction added' }
format.json { render json: @user, status: :created, location: @user }
else
format.html { render 'users/show' }
format.json { render json: @transaction.errors, status: :unprocessable_entity }
end
end
end
def edit
@user = current_user
end
def update
update_ticket_numbers
respond_to do |format|
if @transaction.update_attributes(transaction_params) && @transaction.status == 1
UserMailer.payment_confirmation(@transaction).deliver_later
format.html { redirect_to user_url(current_user), notice: 'Transaction info updated & confirmation email sent to payee' }
format.json { render json: current_user, status: :created, location: current_user }
elsif @transaction.update_attributes(transaction_params) && @transaction.status != 1
format.html { redirect_to user_url(current_user), notice: 'Transaction info updated' }
format.json { render json: current_user, status: :created, location: current_user }
else
format.html { render :edit }
format.json { render json: @transaction.errors, status: :unprocessable_entity }
end
end
end
def destroy
@transaction.destroy
redirect_to user_url(current_user), notice: 'Transaction deleted'
end
private
def load_transaction
@transaction = Transaction.find(params[:id])
end
def transaction_params
params.require(:transaction).permit(:payee, :email, :ministry, :debt,
:quantity, :status, :user_id, :ticket_numbers)
end
def update_ticket_numbers
if @transaction.update_attributes(transaction_params)
if @transaction.ticket_numbers.length < @transaction.quantity
i = @transaction.quantity - @transaction.ticket_numbers.length
i.times.uniq { @transaction.ticket_numbers << rand(100000..999999) }
elsif @transaction.ticket_numbers.length > @transaction.quantity
i = @transaction.ticket_numbers.length - @transaction.quantity
i.times { @transaction.ticket_numbers.pop }
end
end
end
结束
【问题讨论】:
-
如果票号位于单独的模型/表中而不是数组中,使用票号会更容易吗?
-
我可以看到你在做什么,但如果我使用一个单独的模型,它纯粹是为了生成可以在编辑 Transaction.quantity 时添加和删除的票号。当交易在表单上标记为完成时,我还使用 ActionMailer 自动发送电子邮件。票号模型不会过分吗?谢谢!
-
我不是专家,但你不能尝试所有数组的交集并检查交集是否为空以找到唯一性吗?
-
@D_Cheeles 我认为 Brad 的建议最终会少于你目前所走的道路。数据库擅长独特的约束。如果可以的话,你应该利用它。
-
@DCheeles,有一个笑话是“老板,我写了一个程序做错了事,但做的很快”。先把它做好,以后当它成为问题时再担心性能。就像其他人说的那样,我认为您应该为
Ticket创建一个单独的模型并使用唯一索引实现约束。
标签: ruby-on-rails arrays postgresql validation unique